Skip to main content
This guide walks you through connecting Ultraloq locks to Seam and configuring them for use with the Seam API.

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.
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)

Step 2: User Authorization

Direct the user to the Connect Webview URL returned in Step 1. The user will be prompted to:
  1. Sign in to their Ultraloq account
  2. Authorize Seam to access their Ultraloq devices
After authorization, the user is redirected to your custom_redirect_url with the connect_webview_id as a query parameter.

Step 3: Verify Connection

Wait for the Connect Webview status to change to authorized, indicating that the connection was successful. You can either poll the Connect Webview or use webhooks to be notified when the status changes.
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}`)
}

Step 4: List Devices

Once the connection is authorized, retrieve the list of Ultraloq devices associated with the connected account.
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()
}
Expected Output: When you first list Ultraloq devices, they will have the 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.
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!')
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.
For detailed information about timezone configuration, including best practices and troubleshooting, see Configuring Ultraloq Device Timezones.

Step 6: Verify Configuration

After configuring the timezone, verify that the warning has been cleared and the timezone is set correctly.
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!')

Next Steps

Now that your Ultraloq devices are connected and configured, you can perform common operations:

Lock and Unlock Devices

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')

Create Permanent Access Codes

Permanent access codes work indefinitely and do not require timezone configuration:
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}`)

Create Time-Bound Access Codes

Time-bound access codes require timezone configuration (completed in Step 5):
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}`)

Monitor Device Status

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)}`)
}


Troubleshooting

Devices not appearing after connection

If devices don’t appear after connecting your Ultraloq account:
  1. Verify that your locks are connected to Wi-Fi in the Ultraloq mobile app
  2. Ensure your Ultraloq account has access to the locks you’re trying to connect
  3. Wait a few minutes for the initial sync to complete

Warning persists after setting timezone

If the ultraloq_time_zone_unknown warning persists after setting the timezone:
  1. Verify you used a valid IANA timezone string (e.g., "America/New_York", not "EST")
  2. Check that the API call succeeded without errors
  3. 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:
  1. Confirm the device’s timezone is configured (check device.properties.ultraloq_metadata.time_zone)
  2. Verify the ultraloq_time_zone_unknown warning is not present in device.warnings
  3. Ensure you’re providing both starts_at and ends_at parameters