Skip to content

Events and the event feed

Everything that happens to an application’s granted devices (an alert activating, a device leaving a geofence, an automation firing) is written to the organization’s event journal. An application reads it in two ways: by polling the feed, or by receiving each event as a signed webhook. Both carry the same envelope.

Each event has a stable id, a schema_version of integration-event.v1, a type, occurred_at (when the change happened), recorded_at (when it was written) and data, a snapshot taken when the event was written. Apply data as the authoritative state; don’t merge it with older values.

  1. Call GET events/checkpoint to get a cursor at the current head of the journal.
  2. Read the current state you care about (for example the active alerts) through the API.
  3. Call GET events?cursor=…&limit=… (limit 1–100) and apply each event in order. Each page returns data, next_cursor and has_more.
  4. Store next_cursor together with your processed results, in the same transaction, even when the page was empty. Don’t advance it after a failed request.

Things to rely on:

  • Order is commit order, not event time. Apply events in the order the feed returns them.
  • Delivery is at least once. The same id can arrive more than once; record processed IDs and skip repeats.
  • Cursors survive token rotation. Changing the application’s grants invalidates them: the feed answers 409, and you rebuild from a fresh checkpoint.
  • The feed is filtered by device. Events for devices the application isn’t granted never appear.

alert.activated.v1, alert.cleared.v1, alert.acknowledged.v1

An alert was activated, cleared or acknowledged; data is the alert snapshot.

Field in dataTypeDescription
uuidstring (uuid)
episodeinteger
condition"active" | "cleared"
activated_atstring (date-time) or null
cleared_atstring (date-time) or null
acknowledged_atstring (date-time) or null
workflow_uuidstring (uuid)
workflow_namestring
device_uuidstring (uuid)
execution_stopped_reasonstring or nullWhy the alert's workflow stopped evaluating, for example binding_changed.

geofence.entered.v1, geofence.exited.v1, geofence.wandering_started.v1, geofence.wandering_resolved.v1

A device entered or left a geofence (entered, exited), or its geofence rule activated or cleared (wandering_started, wandering_resolved).

Field in dataTypeDescription
uuidstring (uuid)The geofence event's own UUID.
geofence_uuidstring (uuid)
geofence_namestring
assignment_uuidstring (uuid)
device_uuidstring (uuid)
type"entered" | "exited" | "wandering_started" | "wandering_resolved"
source_event_uuidstring (uuid) or nullThe telemetry event that caused the transition, when there was one.
occurred_atstring (date-time)

automation.triggered.v1

A workflow's action.event.v1 node fired.

Field in dataTypeDescription
workflow_uuidstring (uuid)
action_idstringThe action's identity, stable across retries.
namestringThe event name configured on the node.
node_idstring

Instead of polling, an application can register one HTTPS endpoint. Each event is delivered to it in journal order, one at a time.

Signed delivery of one integration event: POST to your endpoint.

Sent to the application's webhook endpoint (HTTPS on port 443, one per application, which must grant events:read and alerts:read) for each event on its granted devices, in journal order, one delivery at a time and at most one send per second per endpoint. The body is the same envelope the feed returns.

Signature. X-Iot-Signature is v1= followed by the hex HMAC-SHA256 of X-Iot-Timestamp + "." + X-Iot-Delivery-Id + "." + raw body, keyed with the endpoint's signing secret. Verify it over the raw bytes before parsing, reject a timestamp more than 300 seconds from your clock, and deduplicate by event id before returning 2xx: a valid signature can be replayed.

Retries. A 2xx response confirms delivery. Timeouts (3 s to connect, 5 s to transfer), network errors, 408, 425, 429 and 5xx are retried after 10 s, 30 s, 2 min and 10 min, up to five attempts within 24 hours; any other status, including a redirect, fails the delivery at once. A delivery that is still being retried holds back newer ones for that endpoint. Saving the endpoint rotates the secret, cancels pending deliveries and starts at the current head of the journal; recover gaps through the feed. Revoking the application or changing its grants disables the endpoint.

HeaderFormatDescription
X-Iot-Delivery-Idstring (uuid)The delivery's UUID, the same on every attempt.
X-Iot-TimestampstringUnix seconds when this attempt was signed.
X-Iot-Signaturestringv1=<hex HMAC-SHA256>.
Example body
{
"id": "0b1c2d3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"schema_version": "integration-event.v1",
"type": "geofence.exited.v1",
"occurred_at": "2026-10-12T08:10:00+00:00",
"recorded_at": "2026-10-12T08:10:01+00:00",
"data": {
"uuid": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"geofence_uuid": "1e2d3c4b-5a69-4788-9a6b-5c4d3e2f1a0b",
"geofence_name": "North paddock",
"assignment_uuid": "4c5d6e7f-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
"device_uuid": "3f8a1c2e-5b6d-4e7f-8a9b-0c1d2e3f4a5b",
"type": "exited",
"source_event_uuid": "5d6e7f8a-9b0c-4d1e-8f2a-3b4c5d6e7f8a",
"occurred_at": "2026-10-12T08:09:58Z"
}
}

Verify the signature on the raw request body, before parsing it:

  1. Read the X-Iot-Timestamp, X-Iot-Delivery-Id and X-Iot-Signature headers.
  2. Reject the request if the timestamp is more than 300 seconds from your clock.
  3. Compute HMAC-SHA256 over timestamp + "." + deliveryId + "." + rawBody, keyed with your endpoint’s signing secret, and hex-encode it.
  4. Compare it with the value after v1= using a constant-time comparison.
  5. Deduplicate by the event’s id before returning a 2xx response: a valid signature can be replayed.

Report a problem with this page