Before You Begin
To follow this guide, you need:- A Seam account (create one at console.seam.co)
- An API key from your Seam workspace
- An Ultraloq account with at least one lock configured
If you’re testing the integration, you can use a sandbox
workspace
with test Ultraloq devices.
Step 1: Create a Connect Webview
Create a Connect Webview to enable the Ultraloq device owner to authorize Seam to access their Ultraloq account.- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
const webview = await seam.connectWebviews.create({
accepted_providers: ['ultraloq'],
custom_redirect_url: 'https://your-app.com/oauth/callback',
})
console.log(webview.url)
curl -X 'POST' \
'https://connect.getseam.com/connect_webviews/create' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"accepted_providers": ["ultraloq"],
"custom_redirect_url": "https://your-app.com/oauth/callback"
}'
from seam import Seam
seam = Seam()
webview = seam.connect_webviews.create(
accepted_providers=["ultraloq"],
custom_redirect_url="https://your-app.com/oauth/callback"
)
print(webview.url)
require "seam"
seam = Seam.new()
webview = seam.connect_webviews.create(
accepted_providers: ["ultraloq"],
custom_redirect_url: "https://your-app.com/oauth/callback"
)
puts webview.url
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
$webview = $seam->connect_webviews->create(
accepted_providers: ["ultraloq"],
custom_redirect_url: "https://your-app.com/oauth/callback"
);
echo $webview->url;
using Seam.Client;
var seam = new SeamClient();
var webview = seam.ConnectWebviews.Create(
acceptedProviders: new[] { "ultraloq" },
customRedirectUrl: "https://your-app.com/oauth/callback"
);
Console.WriteLine(webview.Url);
import com.seam.api.Seam;
import com.seam.api.types.ConnectWebview;
Seam seam = Seam.builder().build();
ConnectWebview webview = seam.connectWebviews().create(
ConnectWebviewsCreateRequest.builder()
.acceptedProviders(List.of("ultraloq"))
.customRedirectUrl("https://your-app.com/oauth/callback")
.build()
);
System.out.println(webview.getUrl());
Step 2: User Authorization
Direct the user to the Connect Webview URL returned in Step 1. The user will be prompted to:- Sign in to their Ultraloq account
- Authorize Seam to access their Ultraloq devices
custom_redirect_url with the connect_webview_id as a query parameter.
Step 3: Verify Connection
Wait for the Connect Webview status to change toauthorized, indicating that the connection was successful. You can either poll the Connect Webview or use webhooks to be notified when the status changes.
- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
// Poll until authorized
const webview = await seam.connectWebviews.get({
connect_webview_id: webview.connect_webview_id,
})
if (webview.status === 'authorized') {
console.log('Connection successful!')
console.log(`Connected account ID: ${webview.connected_account_id}`)
}
curl -X 'POST' \
'https://connect.getseam.com/connect_webviews/get' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{
\"connect_webview_id\": \"${CONNECT_WEBVIEW_ID}\"
}"
from seam import Seam
seam = Seam()
# Poll until authorized
webview = seam.connect_webviews.get(
connect_webview_id=webview.connect_webview_id
)
if webview.status == "authorized":
print("Connection successful!")
print(f"Connected account ID: {webview.connected_account_id}")
require "seam"
seam = Seam.new()
# Poll until authorized
webview = seam.connect_webviews.get(
connect_webview_id: webview.connect_webview_id
)
if webview.status == "authorized"
puts "Connection successful!"
puts "Connected account ID: #{webview.connected_account_id}"
end
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
// Poll until authorized
$webview = $seam->connect_webviews->get(
connect_webview_id: $webview->connect_webview_id
);
if ($webview->status === "authorized") {
echo "Connection successful!\n";
echo "Connected account ID: " . $webview->connected_account_id;
}
using Seam.Client;
var seam = new SeamClient();
// Poll until authorized
var webview = seam.ConnectWebviews.Get(
connectWebviewId: webview.ConnectWebviewId
);
if (webview.Status == "authorized")
{
Console.WriteLine("Connection successful!");
Console.WriteLine($"Connected account ID: {webview.ConnectedAccountId}");
}
import com.seam.api.Seam;
import com.seam.api.types.ConnectWebview;
Seam seam = Seam.builder().build();
// Poll until authorized
ConnectWebview webview = seam.connectWebviews().get(
ConnectWebviewsGetRequest.builder()
.connectWebviewId(webview.getConnectWebviewId())
.build()
);
if (webview.getStatus().equals("authorized")) {
System.out.println("Connection successful!");
System.out.println("Connected account ID: " + webview.getConnectedAccountId());
}
Step 4: List Devices
Once the connection is authorized, retrieve the list of Ultraloq devices associated with the connected account.- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
const devices = await seam.devices.list({
connected_account_id: webview.connected_account_id,
})
for (const device of devices) {
console.log(`Device: ${device.properties.name}`)
console.log(`Device ID: ${device.device_id}`)
console.log(`Warnings:`, device.warnings)
console.log()
}
curl -X 'POST' \
'https://connect.getseam.com/devices/list' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{
\"connected_account_id\": \"${CONNECTED_ACCOUNT_ID}\"
}"
from seam import Seam
seam = Seam()
devices = seam.devices.list(
connected_account_id=webview.connected_account_id
)
for device in devices:
print(f"Device: {device.properties['name']}")
print(f"Device ID: {device.device_id}")
print(f"Warnings: {device.warnings}")
print()
require "seam"
seam = Seam.new()
devices = seam.devices.list(
connected_account_id: webview.connected_account_id
)
devices.each do |device|
puts "Device: #{device.properties['name']}"
puts "Device ID: #{device.device_id}"
puts "Warnings: #{device.warnings}"
puts
end
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
$devices = $seam->devices->list(
connected_account_id: $webview->connected_account_id
);
foreach ($devices as $device) {
echo "Device: " . $device->properties->name . "\n";
echo "Device ID: " . $device->device_id . "\n";
echo "Warnings: " . json_encode($device->warnings) . "\n\n";
}
using Seam.Client;
var seam = new SeamClient();
var devices = seam.Devices.List(
connectedAccountId: webview.ConnectedAccountId
);
foreach (var device in devices)
{
Console.WriteLine($"Device: {device.Properties.Name}");
Console.WriteLine($"Device ID: {device.DeviceId}");
Console.WriteLine($"Warnings: {string.Join(", ", device.Warnings)}");
Console.WriteLine();
}
import com.seam.api.Seam;
import com.seam.api.types.Device;
Seam seam = Seam.builder().build();
List<Device> devices = seam.devices().list(
DevicesListRequest.builder()
.connectedAccountId(webview.getConnectedAccountId())
.build()
);
for (Device device : devices) {
System.out.println("Device: " + device.getProperties().getName());
System.out.println("Device ID: " + device.getDeviceId());
System.out.println("Warnings: " + device.getWarnings());
System.out.println();
}
ultraloq_time_zone_unknown warning:
{
"device_id": "11111111-2222-3333-4444-555555555555",
"device_type": "ultraloq_lock",
"can_program_online_access_codes": true,
"can_remotely_lock": true,
"can_remotely_unlock": true,
"warnings": [
{
"warning_code": "ultraloq_time_zone_unknown",
"message": "Seam does not know the time zone of the Ultraloq device. Set a time zone to enable time-bound access codes."
}
],
"properties": {
"ultraloq_metadata": {
"time_zone": null
}
}
}
Important: The
ultraloq_time_zone_unknown warning indicates that you
must configure the device’s timezone before creating time-bound access codes.
Proceed to Step 5 to configure timezones.Step 5: Configure Device Timezones
This is a required step for Ultraloq devices. You must configure each device’s timezone before you can create time-bound access codes.- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
// Configure timezone for one or more devices
await seam.devices.reportProviderMetadata({
devices: [
{
device_id: device.device_id,
ultraloq_metadata: {
time_zone: 'America/New_York',
},
},
],
})
console.log('Timezone configured successfully!')
curl -X 'POST' \
'https://connect.getseam.com/devices/report_provider_metadata' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{
\"devices\": [
{
\"device_id\": \"${DEVICE_ID}\",
\"ultraloq_metadata\": {
\"time_zone\": \"America/New_York\"
}
}
]
}"
from seam import Seam
seam = Seam()
# Configure timezone for one or more devices
seam.devices.report_provider_metadata(
devices=[
{
"device_id": device.device_id,
"ultraloq_metadata": {
"time_zone": "America/New_York"
}
}
]
)
print("Timezone configured successfully!")
require "seam"
seam = Seam.new()
# Configure timezone for one or more devices
seam.devices.report_provider_metadata(
devices: [
{
device_id: device.device_id,
ultraloq_metadata: {
time_zone: "America/New_York"
}
}
]
)
puts "Timezone configured successfully!"
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
// Configure timezone for one or more devices
$seam->devices->report_provider_metadata(
devices: [
[
"device_id" => $device->device_id,
"ultraloq_metadata" => [
"time_zone" => "America/New_York"
]
]
]
);
echo "Timezone configured successfully!";
using Seam.Client;
var seam = new SeamClient();
// Configure timezone for one or more devices
seam.Devices.ReportProviderMetadata(
devices: new[] {
new DeviceMetadata {
DeviceId = device.DeviceId,
UltraloqMetadata = new UltraloqMetadata {
TimeZone = "America/New_York"
}
}
}
);
Console.WriteLine("Timezone configured successfully!");
import com.seam.api.Seam;
Seam seam = Seam.builder().build();
// Configure timezone for one or more devices
seam.devices().reportProviderMetadata(
DevicesReportProviderMetadataRequest.builder()
.devices(List.of(
DeviceMetadata.builder()
.deviceId(device.getDeviceId())
.ultraloqMetadata(UltraloqMetadata.builder()
.timeZone("America/New_York")
.build())
.build()
))
.build()
);
System.out.println("Timezone configured successfully!");
Valid Timezone Values: Use IANA timezone strings such as
"America/New_York", "Europe/London", or "Asia/Tokyo". Do not use timezone abbreviations like "EST" or "PST".For a complete list of valid timezones, see the IANA Time Zone Database.Step 6: Verify Configuration
After configuring the timezone, verify that the warning has been cleared and the timezone is set correctly.- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
const device = await seam.devices.get({
device_id: device.device_id,
})
// Check that timezone is configured
console.assert(
device.properties.ultraloq_metadata.time_zone === 'America/New_York',
'Timezone should be set',
)
// Check that warning is cleared
const hasWarning = device.warnings.some(
(w) => w.warning_code === 'ultraloq_time_zone_unknown',
)
console.assert(!hasWarning, 'Timezone warning should be cleared')
console.log('✓ Device is ready to create time-bound access codes!')
device=$(curl -X 'POST' \
'https://connect.getseam.com/devices/get' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{
\"device_id\": \"${DEVICE_ID}\"
}")
# Check timezone is set
echo $device | jq '.device.properties.ultraloq_metadata.time_zone'
# Check warnings are cleared
echo $device | jq '.device.warnings'
from seam import Seam
seam = Seam()
device = seam.devices.get(device_id=device.device_id)
# Check that timezone is configured
assert device.properties["ultraloq_metadata"]["time_zone"] == "America/New_York"
# Check that warning is cleared
has_warning = any(
w.warning_code == "ultraloq_time_zone_unknown"
for w in device.warnings
)
assert not has_warning, "Timezone warning should be cleared"
print("✓ Device is ready to create time-bound access codes!")
require "seam"
seam = Seam.new()
device = seam.devices.get(device_id: device.device_id)
# Check that timezone is configured
raise "Timezone not set" unless device.properties["ultraloq_metadata"]["time_zone"] == "America/New_York"
# Check that warning is cleared
has_warning = device.warnings.any? { |w| w.warning_code == "ultraloq_time_zone_unknown" }
raise "Timezone warning not cleared" if has_warning
puts "✓ Device is ready to create time-bound access codes!"
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
$device = $seam->devices->get(device_id: $device->device_id);
// Check that timezone is configured
assert($device->properties->ultraloq_metadata->time_zone === "America/New_York");
// Check that warning is cleared
$hasWarning = false;
foreach ($device->warnings as $warning) {
if ($warning->warning_code === "ultraloq_time_zone_unknown") {
$hasWarning = true;
break;
}
}
assert(!$hasWarning, "Timezone warning should be cleared");
echo "✓ Device is ready to create time-bound access codes!";
using Seam.Client;
var seam = new SeamClient();
var device = seam.Devices.Get(deviceId: device.DeviceId);
// Check that timezone is configured
Debug.Assert(
device.Properties.UltraloqMetadata.TimeZone == "America/New_York",
"Timezone should be set"
);
// Check that warning is cleared
var hasWarning = device.Warnings.Any(
w => w.WarningCode == "ultraloq_time_zone_unknown"
);
Debug.Assert(!hasWarning, "Timezone warning should be cleared");
Console.WriteLine("✓ Device is ready to create time-bound access codes!");
import com.seam.api.Seam;
import com.seam.api.types.Device;
Seam seam = Seam.builder().build();
Device device = seam.devices().get(
DevicesGetRequest.builder()
.deviceId(device.getDeviceId())
.build()
);
// Check that timezone is configured
assert device.getProperties().getUltraloqMetadata().getTimeZone().equals("America/New_York");
// Check that warning is cleared
boolean hasWarning = device.getWarnings().stream()
.anyMatch(w -> w.getWarningCode().equals("ultraloq_time_zone_unknown"));
assert !hasWarning : "Timezone warning should be cleared";
System.out.println("✓ Device is ready to create time-bound access codes!");
Next Steps
Now that your Ultraloq devices are connected and configured, you can perform common operations:Lock and Unlock Devices
- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
// Lock the door
await seam.locks.lockDoor({ device_id: 'your-device-id' })
console.log('Door locked')
// Unlock the door
await seam.locks.unlockDoor({ device_id: 'your-device-id' })
console.log('Door unlocked')
# Lock the door
curl -X 'POST' \
'https://connect.getseam.com/locks/lock_door' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{\"device_id\": \"your-device-id\"}"
# Unlock the door
curl -X 'POST' \
'https://connect.getseam.com/locks/unlock_door' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{\"device_id\": \"your-device-id\"}"
from seam import Seam
seam = Seam()
# Lock the door
seam.locks.lock_door(device_id="your-device-id")
print("Door locked")
# Unlock the door
seam.locks.unlock_door(device_id="your-device-id")
print("Door unlocked")
require "seam"
seam = Seam.new()
# Lock the door
seam.locks.lock_door(device_id: "your-device-id")
puts "Door locked"
# Unlock the door
seam.locks.unlock_door(device_id: "your-device-id")
puts "Door unlocked"
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
// Lock the door
$seam->locks->lock_door(device_id: "your-device-id");
echo "Door locked\n";
// Unlock the door
$seam->locks->unlock_door(device_id: "your-device-id");
echo "Door unlocked\n";
using Seam.Client;
var seam = new SeamClient();
// Lock the door
seam.Locks.LockDoor(deviceId: "your-device-id");
Console.WriteLine("Door locked");
// Unlock the door
seam.Locks.UnlockDoor(deviceId: "your-device-id");
Console.WriteLine("Door unlocked");
import com.seam.api.Seam;
Seam seam = Seam.builder().build();
// Lock the door
seam.locks().lockDoor(LocksLockDoorRequest.builder()
.deviceId("your-device-id")
.build());
System.out.println("Door locked");
// Unlock the door
seam.locks().unlockDoor(LocksUnlockDoorRequest.builder()
.deviceId("your-device-id")
.build());
System.out.println("Door unlocked");
Create Permanent Access Codes
Permanent access codes work indefinitely and do not require timezone configuration:- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
// Create permanent access code
const accessCode = await seam.accessCodes.create({
device_id: 'your-device-id',
name: 'Maintenance Team',
code: '1234', // Optional: auto-generated if omitted
})
console.log(`Created permanent code: ${accessCode.code}`)
curl -X 'POST' \
'https://connect.getseam.com/access_codes/create' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"device_id": "your-device-id",
"name": "Maintenance Team",
"code": "1234"
}'
from seam import Seam
seam = Seam()
# Create permanent access code
access_code = seam.access_codes.create(
device_id="your-device-id",
name="Maintenance Team",
code="1234" # Optional: auto-generated if omitted
)
print(f"Created permanent code: {access_code.code}")
require "seam"
seam = Seam.new()
# Create permanent access code
access_code = seam.access_codes.create(
device_id: "your-device-id",
name: "Maintenance Team",
code: "1234" # Optional: auto-generated if omitted
)
puts "Created permanent code: #{access_code.code}"
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
// Create permanent access code
$accessCode = $seam->access_codes->create(
device_id: "your-device-id",
name: "Maintenance Team",
code: "1234" // Optional: auto-generated if omitted
);
echo "Created permanent code: " . $accessCode->code . "\n";
using Seam.Client;
var seam = new SeamClient();
// Create permanent access code
var accessCode = seam.AccessCodes.Create(
deviceId: "your-device-id",
name: "Maintenance Team",
code: "1234" // Optional: auto-generated if omitted
);
Console.WriteLine($"Created permanent code: {accessCode.Code}");
import com.seam.api.Seam;
import com.seam.api.types.AccessCode;
Seam seam = Seam.builder().build();
// Create permanent access code
AccessCode accessCode = seam.accessCodes().create(
AccessCodesCreateRequest.builder()
.deviceId("your-device-id")
.name("Maintenance Team")
.code("1234") // Optional: auto-generated if omitted
.build()
);
System.out.println("Created permanent code: " + accessCode.getCode());
Create Time-Bound Access Codes
Time-bound access codes require timezone configuration (completed in Step 5):- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
// Define time range
const startsAt = new Date(Date.now() + 24 * 60 * 60 * 1000)
const endsAt = new Date(startsAt.getTime() + 2 * 24 * 60 * 60 * 1000)
// Create time-bound access code
const accessCode = await seam.accessCodes.create({
device_id: 'your-device-id',
name: 'Weekend Guest',
starts_at: startsAt.toISOString(),
ends_at: endsAt.toISOString(),
})
console.log(`Created time-bound code: ${accessCode.code}`)
console.log(`Active from ${accessCode.starts_at} to ${accessCode.ends_at}`)
# Calculate timestamps
STARTS_AT=$(date -u -d '+1 day' '+%Y-%m-%dT%H:%M:%SZ')
ENDS_AT=$(date -u -d '+3 days' '+%Y-%m-%dT%H:%M:%SZ')
curl -X 'POST' \
'https://connect.getseam.com/access_codes/create' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{
\"device_id\": \"your-device-id\",
\"name\": \"Weekend Guest\",
\"starts_at\": \"${STARTS_AT}\",
\"ends_at\": \"${ENDS_AT}\"
}"
from seam import Seam
from datetime import datetime, timedelta
seam = Seam()
# Define time range
starts_at = datetime.utcnow() + timedelta(days=1)
ends_at = starts_at + timedelta(days=2)
# Create time-bound access code
access_code = seam.access_codes.create(
device_id="your-device-id",
name="Weekend Guest",
starts_at=starts_at.isoformat() + "Z",
ends_at=ends_at.isoformat() + "Z"
)
print(f"Created time-bound code: {access_code.code}")
print(f"Active from {access_code.starts_at} to {access_code.ends_at}")
require "seam"
require "time"
seam = Seam.new()
# Define time range
starts_at = Time.now.utc + (24 * 60 * 60)
ends_at = starts_at + (2 * 24 * 60 * 60)
# Create time-bound access code
access_code = seam.access_codes.create(
device_id: "your-device-id",
name: "Weekend Guest",
starts_at: starts_at.iso8601,
ends_at: ends_at.iso8601
)
puts "Created time-bound code: #{access_code.code}"
puts "Active from #{access_code.starts_at} to #{access_code.ends_at}"
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
// Define time range
$startsAt = new DateTime('+1 day', new DateTimeZone('UTC'));
$endsAt = (clone $startsAt)->add(new DateInterval('P2D'));
// Create time-bound access code
$accessCode = $seam->access_codes->create(
device_id: "your-device-id",
name: "Weekend Guest",
starts_at: $startsAt->format(DateTime::ATOM),
ends_at: $endsAt->format(DateTime::ATOM)
);
echo "Created time-bound code: " . $accessCode->code . "\n";
echo "Active from " . $accessCode->starts_at . " to " . $accessCode->ends_at . "\n";
using Seam.Client;
using System;
var seam = new SeamClient();
// Define time range
var startsAt = DateTime.UtcNow.AddDays(1);
var endsAt = startsAt.AddDays(2);
// Create time-bound access code
var accessCode = seam.AccessCodes.Create(
deviceId: "your-device-id",
name: "Weekend Guest",
startsAt: startsAt,
endsAt: endsAt
);
Console.WriteLine($"Created time-bound code: {accessCode.Code}");
Console.WriteLine($"Active from {accessCode.StartsAt} to {accessCode.EndsAt}");
import com.seam.api.Seam;
import com.seam.api.types.AccessCode;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
Seam seam = Seam.builder().build();
// Define time range
Instant startsAt = Instant.now().plus(1, ChronoUnit.DAYS);
Instant endsAt = startsAt.plus(2, ChronoUnit.DAYS);
// Create time-bound access code
AccessCode accessCode = seam.accessCodes().create(
AccessCodesCreateRequest.builder()
.deviceId("your-device-id")
.name("Weekend Guest")
.startsAt(startsAt.toString())
.endsAt(endsAt.toString())
.build()
);
System.out.println("Created time-bound code: " + accessCode.getCode());
System.out.println("Active from " + accessCode.getStartsAt() + " to " + accessCode.getEndsAt());
Monitor Device Status
- JavaScript
- cURL
- Python
- Ruby
- PHP
- C#
- Java
import { Seam } from 'seam'
const seam = new Seam()
const device = await seam.devices.get({ device_id: 'your-device-id' })
// Check lock status
console.log(`Lock status: ${device.properties.locked}`)
// Check online status
console.log(`Online: ${device.properties.online}`)
// Check battery level (if available)
if (device.properties.battery_level) {
console.log(`Battery level: ${device.properties.battery_level}`)
}
// Check for warnings
if (device.warnings.length > 0) {
console.log(`Warnings: ${device.warnings.map((w) => w.warning_code)}`)
}
device=$(curl -X 'POST' \
'https://connect.getseam.com/devices/get' \
-H 'accept: application/json' \
-H "Authorization: Bearer ${SEAM_API_KEY}" \
-H 'Content-Type: application/json' \
-d "{\"device_id\": \"your-device-id\"}")
# Check lock status
echo $device | jq '.device.properties.locked'
# Check online status
echo $device | jq '.device.properties.online'
# Check battery level
echo $device | jq '.device.properties.battery_level'
# Check warnings
echo $device | jq '.device.warnings'
from seam import Seam
seam = Seam()
device = seam.devices.get(device_id="your-device-id")
# Check lock status
print(f"Lock status: {device.properties['locked']}")
# Check online status
print(f"Online: {device.properties['online']}")
# Check battery level (if available)
if 'battery_level' in device.properties:
print(f"Battery level: {device.properties['battery_level']}")
# Check for warnings
if device.warnings:
print(f"Warnings: {[w.warning_code for w in device.warnings]}")
require "seam"
seam = Seam.new()
device = seam.devices.get(device_id: "your-device-id")
# Check lock status
puts "Lock status: #{device.properties['locked']}"
# Check online status
puts "Online: #{device.properties['online']}"
# Check battery level (if available)
if device.properties['battery_level']
puts "Battery level: #{device.properties['battery_level']}"
end
# Check for warnings
if device.warnings.any?
puts "Warnings: #{device.warnings.map(&:warning_code)}"
end
<?php
require 'vendor/autoload.php';
use Seam\SeamClient;
$seam = new SeamClient();
$device = $seam->devices->get(device_id: "your-device-id");
// Check lock status
echo "Lock status: " . ($device->properties->locked ? "locked" : "unlocked") . "\n";
// Check online status
echo "Online: " . ($device->properties->online ? "yes" : "no") . "\n";
// Check battery level (if available)
if (isset($device->properties->battery_level)) {
echo "Battery level: " . $device->properties->battery_level . "\n";
}
// Check for warnings
if (count($device->warnings) > 0) {
$warningCodes = array_map(fn($w) => $w->warning_code, $device->warnings);
echo "Warnings: " . implode(", ", $warningCodes) . "\n";
}
using Seam.Client;
using System.Linq;
var seam = new SeamClient();
var device = seam.Devices.Get(deviceId: "your-device-id");
// Check lock status
Console.WriteLine($"Lock status: {device.Properties.Locked}");
// Check online status
Console.WriteLine($"Online: {device.Properties.Online}");
// Check battery level (if available)
if (device.Properties.BatteryLevel.HasValue)
{
Console.WriteLine($"Battery level: {device.Properties.BatteryLevel}");
}
// Check for warnings
if (device.Warnings.Any())
{
var warningCodes = string.Join(", ", device.Warnings.Select(w => w.WarningCode));
Console.WriteLine($"Warnings: {warningCodes}");
}
import com.seam.api.Seam;
import com.seam.api.types.Device;
import java.util.stream.Collectors;
Seam seam = Seam.builder().build();
Device device = seam.devices().get(
DevicesGetRequest.builder()
.deviceId("your-device-id")
.build()
);
// Check lock status
System.out.println("Lock status: " + device.getProperties().getLocked());
// Check online status
System.out.println("Online: " + device.getProperties().getOnline());
// Check battery level (if available)
if (device.getProperties().getBatteryLevel() != null) {
System.out.println("Battery level: " + device.getProperties().getBatteryLevel());
}
// Check for warnings
if (!device.getWarnings().isEmpty()) {
String warningCodes = device.getWarnings().stream()
.map(w -> w.getWarningCode())
.collect(Collectors.joining(", "));
System.out.println("Warnings: " + warningCodes);
}
Related Resources
- Creating Ultraloq Access Codes - Detailed guide on permanent and time-bound access codes
- Configuring Ultraloq Device Timezones - Complete timezone configuration reference
- Lock and Unlock Operations - General smart lock control documentation
- Access Codes Overview - Understanding access code management
Troubleshooting
Devices not appearing after connection
If devices don’t appear after connecting your Ultraloq account:- Verify that your locks are connected to Wi-Fi in the Ultraloq mobile app
- Ensure your Ultraloq account has access to the locks you’re trying to connect
- Wait a few minutes for the initial sync to complete
Warning persists after setting timezone
If theultraloq_time_zone_unknown warning persists after setting the timezone:
- Verify you used a valid IANA timezone string (e.g.,
"America/New_York", not"EST") - Check that the API call succeeded without errors
- Refresh the device by calling
seam.devices.get()to get the latest state
Time-bound access codes fail to create
If you receive an error when creating time-bound access codes:- Confirm the device’s timezone is configured (check
device.properties.ultraloq_metadata.time_zone) - Verify the
ultraloq_time_zone_unknownwarning is not present indevice.warnings - Ensure you’re providing both
starts_atandends_atparameters

