Skip to main content
Version: 1.0

Streaming API

The Streaming API allows your application to send commands and listen for events over a live WebSocket connection. It can be used in situations that would otherwise require polling at regular intervals, such as displaying real-time status information in a dashboard. In most other situations, the REST API and webhooks will provide superior functionality and reliability.

Setup

Since the Streaming API is powered by Socket.IO, the easiest way to interact with it is through a Socket.IO client, which is available in a variety of languages. However, any WebSocket library can also be used. The following Node.js examples show how the Streaming API can be used with both socket.io-client (the official Socket.IO client library) and ws (a generic WebSocket library).

Establishing a connection

The first step is to install the latest 2.x version of the Socket.IO client.

npm install socket.io-client@v2-latest

You can now establish a socket connection using your panel_id and a valid panel_token. See the code tutorial for instructions on requesting panel tokens.

const io = require("socket.io-client")
const socket = io(`wss://panel-${panel_id}.pdk.io?token=${panel_token}`)

Listening for events

Once a socket connection is established, you can begin listening for events in the access control system. The following example listens for door.request.allowed events, which are emitted when credential holders are granted access.

socket.on("door.request.allowed", (event) => {
console.log(event)
})

When an event occurs, the event is passed into the callback function provided to the event listener. The body of the event includes details related to the corresponding event topic. In this example, the event topic is door.request.allowed and the body includes details about the person (the credential holder) and the door (the device that was accessed).

{
"id": "0153463f-d9ba-435f-b099-60f2b7c8d7e3",
"topic": "door.request.allowed",
"body": {
"doorId": 1,
"personId": 1,
"requestFactor": "PIN_ONLY",
"person": {
"id": 1,
"firstName": "Postman",
"lastName": "Test",
"enabled": true,
"partition": 0,
"activeDate": null,
"expireDate": null,
"metadata": {}
},
"door": {
"id": 1,
"name": "Postman Test",
"port": 1,
"metadata": {},
"connection": 1,
"partitions": [0]
}
},
"occurred": "2023-05-03 19:04:55",
"metadata": {
"occurred": 1683165895729,
"doorName": "Postman Test",
"personName": "Postman Test"
}
}

Sending commands

You can also send commands to the access control system. The following example opens a given device for 3 seconds.

socket.emit("command", {
id: crypto.randomUUID(),
topic: "door.try.dwellopen",
body: {
doorId: device_id,
dwell: 30
}
})

The required id property can be used along with the command.result.succeed event in order to confirm that a particular command has been successfully executed.

Renewing the panel token

When an event occurs after a panel token has expired, an invalidToken event will be emitted in its place. You can renew panel tokens automatically by listening for invalidToken events and issuing the renewedToken command. Once a new token is received, the Streaming API will immediately emit any events that occurred while the previous token was expired.

socket.on("invalidToken", async (event) => {
const panel_token = await get_panel_token()
socket.emit("renewedToken", { token: panel_token })
})

Events

In addition to the standard Socket.IO events, your application can also listen for the following access control events.

tip

The Streaming API only supports a small subset of events. For a complete set of events, use webhooks instead.

command.result.succeed

This event is emitted when a command executes successfully.

{
"id": "15849618-57a5-4f61-99e4-fde5c7460f4c",
"topic": "command.result.succeed",
"body": {
"commandId": "c4a4bd80-1ffa-4041-80b4-f2b3d7770294"
},
"occurred": "2023-05-04 17:59:16",
"metadata": {
"occurred": 1683248356916
}
}

door.alarm.forced

This event is emitted when a device has been forced open.

{
"topic": "door.alarm.forced",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.alarm.forced.cleared

This event is emitted when a forced alarm is cleared, which can be done by sending the door.alarm.forced.clear command.

{
"topic": "door.alarm.forced.cleared",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.alarm.propped.off

This event is emitted when a device propped alarm is cleared.

{
"topic": "door.alarm.propped.off",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.alarm.propped.on

This event is emitted when a device has been propped open.

{
"topic": "door.alarm.propped.on",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.forceclose.off

This event is emitted when the force close feature is disabled on a device.

{
"topic": "door.forceclose.off",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.forceclose.on

This event is emitted when the force close feature is enabled on a device.

{
"topic": "door.forceclose.on",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.input.dps.closed

This event is emitted when a door position sensor (DPS) detects that a device has been closed.

{
"topic": "door.input.dps.closed",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.input.dps.opened

This event is emitted when a door position sensor (DPS) detects that a device has been opened.

{
"topic": "door.input.dps.opened",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.input.relay.off

This event is emitted when a device relay changes to an off state.

{
"topic": "door.input.relay.off",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.input.relay.on

This event is emitted when a device relay changes to an on state.

{
"topic": "door.input.relay.on",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.input.rex.off

This event is emitted when the request to exit sensor is deactivated.

{
"topic": "door.input.rex.off",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.input.rex.on

This event is emitted when the request to exit sensor is activated.

{
"topic": "door.input.rex.on",
"body": {
"doorId": 1,
"door": {
"id": 1,
"name": "Postman Test",
"connection": 1,
"port": 1,
"partitions": [0],
"metadata": {}
}
},
"occurred": "2023-05-04 17:59:16"
}

door.request.allowed

This event is emitted when a credential holder is granted access.

{
"id": "0153463f-d9ba-435f-b099-60f2b7c8d7e3",
"topic": "door.request.allowed",
"body": {
"doorId": 1,
"personId": 1,
"requestFactor": "PIN_ONLY",
"person": {
"id": 1,
"firstName": "Postman",
"lastName": "Test",
"enabled": true,
"partition": 0,
"activeDate": null,
"expireDate": null,
"metadata": {}
},
"door": {
"id": 1,
"name": "Postman Test",
"port": 1,
"metadata": {},
"connection": 1,
"partitions": [0]
}
},
"occurred": "2023-05-03 19:04:55",
"metadata": {
"occurred": 1683165895729,
"doorName": "Postman Test",
"personName": "Postman Test"
}
}

door.request.denied

This event is emitted when a credential holder is recognized but is denied access due to a deny rule.

{
"id": "3a5910ad-8635-4e56-92ac-25c6c24a5775",
"topic": "door.request.denied",
"body": {
"doorId": 1,
"personId": 1,
"requestFactor": "PIN_ONLY",
"explicit": true,
"person": {
"id": 1,
"firstName": "Postman",
"lastName": "Test",
"enabled": true,
"partition": 0,
"activeDate": null,
"expireDate": null,
"metadata": {}
},
"door": {
"id": 28,
"name": "Postman Test",
"port": 1,
"metadata": {},
"connection": 16,
"partitions": [0]
}
},
"occurred": "2023-05-04 18:49:42",
"metadata": {
"occurred": 1683251382729,
"doorName": "Postman Test",
"personName": "Postman Test"
}
}

door.request.unknown

This event is emitted when a credential is presented but the credential holder is not recognized.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.request.unknown",
"body": {
"doorId": 1,
"pin": "1234",
"door": {
"id": 1,
"name": "Postman Test",
"port": 1,
"metadata": {},
"connection": 1,
"partitions": [0]
}
},
"metadata": {
"occurred": 1683251028581,
"doorName": "Postman Test"
},
"occurred": "2023-05-04 18:43:48"
}

endpoint.discovered

This event is emitted in response to the endpoint.discover command. One event is emitted per endpoint.

{
"topic": "endpoint.discovered",
"body": {
"ioLinkId": 1,
"address": "0013a200400a393b",
"ioLinkType": "wirelessCoordinator",
"ioLinkName": "wimac",
"doors": [
{
"id": 1,
"port": 1,
"name": "Postman Test"
}
]
}
}

endpoint.signal

This event is emitted in response to the endpoint.querysignal command. One event is emitted per endpoint.

{
"topic": "endpoint.signal",
"body": {
"ioLinkId": 1,
"address": "0013a200400a393b",
"dbGain": 40
},
"occurred": "2023-05-04 18:43:48"
}

liveEvent

This aggregate event is emitted when auditable access events occur. Each event includes a description that can be used in human-readable event streams.

{
"info": "Person \"%s\" has requested access to the device \"%s\". Access allowed. Person used PIN for requesting access.",
"occurred": "2023-05-03 19:20:50",
"topic": "door.request.allowed",
"placeholders": [
{
"text": "Postman Test",
"id": 1,
"type": "person"
},
{
"text": "Postman Test",
"id": 1,
"type": "door"
}
],
"photo": null
}

migration.completed

This event is emitted when a migrated system has been activated.

{
"systemId": "ea5df7cb-8ea9-443d-9866-b5c44c05b46d"
}

migration.staged

This event is emitted when a migrated system has been fully staged.

{
"systemId": "ea5df7cb-8ea9-443d-9866-b5c44c05b46d"
}

migration.started

This event is emitted when a migration has been initiated. No body is provided with this event.

migration.task.completed

This event is emitted when a migration task has completed. Valid tasks are EXPORT_LEGACY_DATA, CREATE_CUSTOMER, CREATE_SYSTEM, TRANSFORM_SCHEMA, IMPORT_SYSTEM_DATA, and ACTIVATE_SYSTEM.

{
"task": "EXPORT_LEGACY_DATA"
}

migration.task.started

This event is emitted when a migration task has started. Valid tasks are EXPORT_LEGACY_DATA, CREATE_CUSTOMER, CREATE_SYSTEM, TRANSFORM_SCHEMA, IMPORT_SYSTEM_DATA, and ACTIVATE_SYSTEM.

{
"task": "EXPORT_LEGACY_DATA"
}

serverError

This event is emitted when an error occurs on the server.

{
"message": "Command is not supported."
}

Commands

The following access control commands can be sent through the Streaming API.

tip

The Streaming API only supports a small subset of commands. For a complete set of commands, use the REST API instead.

door.actuate.close

This command closes the specified device.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.actuate.close",
"body": {
"doorId": 1
}
}

door.actuate.dnd

This command toggles the do not disturb setting on the specified device.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.actuate.dnd",
"body": {
"doorId": 1
}
}

door.actuate.forcetoggle

This command toggles the state of the specified device.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.actuate.forcetoggle",
"body": {
"doorId": 1
}
}

door.actuate.open

This command opens the specified device.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.actuate.open",
"body": {
"doorId": 1
}
}

door.alarm.forced.clear

This command clears the forced alarm for the specified device.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.alarm.forced.clear",
"body": {
"doorId": 1
}
}

door.try.dwellopen

This command opens a device for a period of time before automatically closing it. The dwell parameter is specified in units of 0.1 seconds, so a value of 30 would cause the device to remain open for 3 seconds.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.try.dwellopen",
"body": {
"doorId": 6,
"dwell": 30
}
}

door.try.open

This command opens a device using the default dwell time.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "door.try.open",
"body": {
"doorId": 1
}
}

endpoint.discover

This command initiates the discovery of all connected wireless endpoints.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "endpoint.discover",
"body": {}
}

endpoint.querysignal

This command queries the last-hop signal strength of the specified wireless endpoint.

{
"id": "883296f4-2a11-4d01-92ea-aa77d029322f",
"topic": "endpoint.querysignal",
"body": {
"ioLinkId": 1, // The connection ID of the wireless coordinator
"address": "0013a200400a393b", // The MAC address of the wireless device
"actuateRelay": false, // Whether to actuate the signalling relay on and off
"relayDwell": 5 // How long to hold the signaling relay on
}
}