REST API
A versioned HTTP API covers the whole platform. Everything is organization-scoped and isolated by row-level security, so a request only ever sees its own tenant's data.
Base path and versioning
The API is served under /api, and resources are versioned under /v1 — so effective paths look like /api/v1/devices. Schema exports live at /api/schemas.
Authentication
Three schemes coexist, all stateless:
- User sessions — the web app authenticates users and calls the API with a signed JWT.
- API keys — machine clients send
Authorization: Bearer sk_…. Keys are organization-scoped. This is what the CLI uses. - Devices — devices don't use either. They provision a certificate with a one-time registration token and then talk to the message broker over mutual TLS.
Every authenticated request resolves to an organization, and all data access is filtered to that organization in the database.
Examples
Every call carries an API key in the Authorization header. Here's the full round trip for two common tasks.
Register a device — create a one-time token, then hand it to the device:
curl -X POST https://<host>/api/v1/devices/registration/tokens \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{ "deviceName": "warehouse-gateway-01" }'
{
"token": "a1b2c3d4-….d1e2f3a4-….J4kQ7m…",
"deviceId": "d1e2f3a4-e5f6-7890-abcd-ef1234567890",
"deviceName": "warehouse-gateway-01",
"provisionEndpoint": "https://<host>/api/v1/devices/provision",
"expiresAt": "2024-01-16T10:30:00Z"
}
The token is shown once — flash it into the device, which exchanges it at provisionEndpoint for a certificate.
Export data — submit a job, then poll until it's ready:
curl -X POST https://<host>/api/v1/exports \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{
"scopeType": "DEVICE",
"scopeId": "d1e2f3a4-e5f6-7890-abcd-ef1234567890",
"from": "2024-01-01T00:00:00Z",
"to": "2024-02-01T00:00:00Z",
"includes": ["READINGS", "ANNOTATIONS"]
}'
The job is created as PENDING (HTTP 201):
{
"id": "ex1a2b3c-4d5e-6789-abcd-ef0123456789",
"scopeType": "DEVICE",
"scopeId": "d1e2f3a4-e5f6-7890-abcd-ef1234567890",
"from": "2024-01-01T00:00:00Z",
"to": "2024-02-01T00:00:00Z",
"includes": ["READINGS", "ANNOTATIONS"],
"status": "PENDING",
"requestedBy": "user_8f2c…",
"createdAt": "2024-01-15T10:30:00Z"
}
Poll GET /api/v1/exports/{id} until status is READY; the response then carries a fresh, time-limited downloadUrl:
{
"id": "ex1a2b3c-4d5e-6789-abcd-ef0123456789",
"status": "READY",
"sizeBytes": 184320,
"readingCount": 44021,
"annotationCount": 12,
"completedAt": "2024-01-15T10:30:42Z",
"expiresAt": "2024-01-16T10:30:42Z",
"downloadUrl": "https://<host>/…/exports/ex1a2b3c-….zip?X-Amz-Signature=…"
}
Resource groups
The main groups, each under /api/v1:
- Devices & topology —
/devices,/components,/sensors,/device-groups,/sites,/devices/{id}/health - Provisioning —
/devices/registration,/devices/provision - Config & commands —
/config-artefacts,/desired-state-bindings,/devices/{id}/commands - Profiles & packs —
/sensor-profiles,/device-profiles,/packs - Readings —
/readings(raw, aggregated, stats, batch) - Alerting —
/alert-rules,/alerts,/notification-channels,/events - Analytics —
/annotations,/annotation-classes,/reference-pairs - Dashboards —
/dashboards - Media —
/cameras,/captures,/media-capture-rules,/dvr-clip-requests,/live - Data —
/exports,/admin/quarantine - Firmware & billing —
/firmware,/billing
OpenAPI
A machine-readable OpenAPI specification is published at /api/v3/api-docs in environments configured to expose it. It's the source for the CLI's typed client and bundled reference.
See the Glossary for what each resource represents.