Webhooks & Events

How to send real-time device updates to Seam through a single webhook endpoint. Seam uses webhook events to keep device state accurate without polling and to correlate lock actions, access-code changes, and connectivity updates.


Webhook registration

Seam registers one webhook URL per environment (production, staging, or development).

Your API should deliver all events to the provided URL.

Correct behavior:

  • one webhook URL per Seam environment

  • no per-user or per-account webhook registration

  • Seam maps each incoming event to the correct connected account internally

Your API should allow Seam to register this URL and specify which event types it wants to receive.

Webhook registration request

POST https://devicecloud.example.com/webhooks

{
  "url": "https://webhooks.seam.co/provider_events",
  "events": [
    "device.added",
    "device.removed",
    "device.online",
    "device.offline",
    "device.low_battery",
    "lock.action_completed",
    "access_code.created",
    "access_code.updated",
    "access_code.deleted",
    "access_code.used",
    "access_code.incorrect_attempt"
  ]
}

Webhook registration response

{
  "webhook_id": "wh_11828",
  "status": "active"
}

Event Delivery

Your API should POST events to the registered webhook URL as they occur.

Example delivery

POST https://webhooks.seam.co/provider_events

{
  "event_type": "device.online",
  "device_id": "lock_491829",
  "timestamp": "2025-05-22T10:48:18Z"
}

A 2xx response means the event was accepted.

Retry behavior

Your API should retry event delivery when Seam returns a non-2xx status.

  • Exponential backoff

  • Retries for at least 24 hours

  • Payload unchanged

  • Maintain chronological order when possible


Event Examples

Device connectivity events

Device online

{
  "event_type": "device.online",
  "device_id": "lock_491829",
  "timestamp": "2025-05-22T10:48:18Z"
}

Device offline

{
  "event_type": "device.offline",
  "device_id": "lock_491829",
  "timestamp": "2025-05-22T10:45:01Z"
}

Bridge or hub offline

{
  "event_type": "bridge.offline",
  "bridge_id": "bridge_99211",
  "timestamp": "2025-05-22T10:45:01Z"
}

Device time is wrong

{
  "event_type": "device.time_wrong",
  "device_id": "lock_491829",
  "timestamp": "2025-05-22T10:45:01Z"
}

Lock action events

Successful action

{
  "event_type": "lock.action_completed",
  "device_id": "lock_491829",
  "action_id": "act_39102",
  "action": "unlock",
  "status": "success",
  "performed_via": "pin_code",
  "timestamp": "2025-05-22T10:45:12Z"
}

Failed action

{
  "event_type": "lock.action_completed",
  "device_id": "lock_491829",
  "action_id": "act_39102",
  "action": "unlock",
  "status": "failed",
  "error_code": "LOCK_JAMMED",
  "message": "The deadbolt could not retract.",
  "timestamp": "2025-05-22T10:46:02Z"
}

Access code lifecycle events

Code created

{
  "event_type": "access_code.created",
  "device_id": "lock_491829",
  "access_code_id": "ac_55301",
  "code": "4829",
  "status": "success",
  "starts_at": "2025-05-22T15:00:00Z",
  "ends_at": "2025-05-25T11:00:00Z",
  "timestamp": "2025-05-22T14:59:12Z"
}

Code updated

{
  "event_type": "access_code.updated",
  "access_code_id": "ac_55301",
  "status": "success",
  "timestamp": "2025-05-22T16:01:12Z"
}

Code deleted

{
  "event_type": "access_code.deleted",
  "access_code_id": "ac_55301",
  "status": "success",
  "timestamp": "2025-05-25T11:02:44Z"
}

Access code usage events

Successful usage

{
  "event_type": "access_code.used",
  "device_id": "lock_491829",
  "access_code_id": "ac_55301",
  "timestamp": "2025-05-23T08:15:32Z"
}

Incorrect PIN attempt

{
  "event_type": "access_code.incorrect_attempt",
  "device_id": "lock_491829",
  "timestamp": "2025-05-23T08:16:02Z"
}

Event format consistency

All events should follow a standard shape:

{
  "event_type": "string",
  "device_id": "string or null",
  "timestamp": "ISO-8601 timestamp",
  "data": { }
}

Last updated

Was this helpful?