Skip to content

Message Format

All WebSocket text messages use JSON. The top-level type identifies the message direction. topic is used only by requests and events.

typeDirectionDescription
requestClient to serviceStarts a request
replyService to clientReplies to a request
eventService to clientPushes an event

Request

json
{
  "type": "request",
  "requestId": "req_state_001",
  "topic": "device.state.get",
  "data": {
    "deviceId": "abc123456789"
  }
}
FieldTypeRequiredDescription
typestringYesFixed as request
requestIdstringYesClient-generated ID that should be unique within the connection
topicstringYesRequest topic
dataobjectYesRequest parameters

Device write operations use device.operation.execute. data.operation.name selects the operation:

json
{
  "type": "request",
  "requestId": "req_relay_001",
  "topic": "device.operation.execute",
  "data": {
    "deviceId": "abc123456789",
    "idempotencyKey": "idem_relay_001",
    "operation": {
      "name": "device.relay.set",
      "params": {
        "relays": [
          { "index": 1, "action": "ON" }
        ]
      }
    }
  }
}

Reply

A reply is correlated by requestId, so it does not repeat topic and does not use success or a nested error object.

Successful reply:

json
{
  "type": "reply",
  "requestId": "req_state_001",
  "code": "SUCCESS",
  "message": "OK.",
  "data": {
    "deviceId": "abc123456789",
    "status": "ONLINE",
    "peripherals": {
      "relays": [
        { "index": 1, "on": true }
      ]
    },
    "stateUpdatedAt": "2026-07-15T08:30:00Z"
  }
}

Accepted command:

json
{
  "type": "reply",
  "requestId": "req_relay_001",
  "code": "COMMAND_ACCEPTED",
  "message": "Command accepted.",
  "data": {
    "command": {
      "id": "cmd_01HX...",
      "deviceId": "abc123456789",
      "operation": "device.relay.set",
      "status": "SUCCESS",
      "params": {
        "relays": [
          { "index": 1, "action": "ON" }
        ]
      },
      "createdAt": "2026-07-15T08:30:00Z"
    }
  }
}

Error reply:

json
{
  "type": "reply",
  "requestId": "req_relay_001",
  "code": "AUTH_SCOPE_DENIED",
  "message": "This operation requires the device:control permission. Update the API Client permissions in the Developer Console and obtain a new access token.",
  "data": {
    "requiredScope": "device:control"
  }
}
FieldTypeRequiredDescription
typestringYesFixed as reply
requestIdstringYesThe matching request ID
codestringYesSUCCESS, COMMAND_ACCEPTED, or an error code
messagestringYesHuman-readable context for display and troubleshooting
dataobjectNoSuccess data or structured error details

Branch on code, not on the text in message.

Event

json
{
  "type": "event",
  "topic": "device.state.changed",
  "data": {
    "deviceId": "abc123456789",
    "occurredAt": "2026-07-15T08:30:00Z",
    "changes": [
      { "type": "relay", "indexes": [1] }
    ],
    "peripherals": {
      "relays": [
        { "index": 1, "on": true }
      ]
    },
    "stateUpdatedAt": "2026-07-15T08:30:00Z"
  }
}
FieldTypeRequiredDescription
typestringYesFixed as event
topicstringYesEvent topic
dataobjectYesEvent data

Events do not correspond to a request and therefore have no requestId. WebSocket events have no history replay. Query important device state after reconnecting.

See Peripheral State Reference for peripheral fields.

Naming Rules

  • type is one of request, reply, or event
  • topic uses lowercase words separated by dots
  • Write operations use device.operation.execute and place the operation in operation.name
  • Event topics describe facts that occurred, such as device.state.changed and device.connection.online
  • Timestamps use RFC3339 UTC strings
  • JSON fields use camelCase
  • Clients should ignore newly added fields they do not recognize
Docs buildVersion v1.3.6-20260720-180213-70
Copyright © 2026 WLTE