All responses use JSON except static assets and the SSE stream. Mutation errors include an error message and, when available, a stable code.
| Status | Meaning |
|---|---|
400 |
Invalid JSON, field, timestamp, URL, query, status, or progress |
404 |
Device, alert, command, or route not found |
409 |
State conflict, active OTA conflict, skipped transition, or progress regression |
413 |
JSON body exceeds 64 KiB |
500 |
Unexpected server or persistence failure |
GET /api/devicesreturns{ devices }with each device's latest telemetry.GET /api/devices/:idreturns{ device }withrecentTelemetry, activependingCommands, and completecommandHistory.POST /api/telemetryrequiresdeviceIdand ametricsobject containing finite numeric values.reportedStateis optional.- Unknown device IDs are registered automatically on first telemetry.
GET /api/alertslists all alerts;?status=open|acknowledged|resolvedfilters them.POST /api/alerts/:id/acknowledgeaccepts{ "actor": "operator" }.POST /api/alerts/:id/resolveaccepts{ "actor": "operator", "reason": "Inspection complete" }.
Manual lifecycle:
open -> acknowledged -> resolved
Repeated identical acknowledgement or resolution is idempotent. Manual resolution requires prior acknowledgement. Connectivity alerts may be resolved directly by the system when telemetry resumes.
POST /api/ota-jobsacceptsdeviceId,targetVersion, and optionalartifactUrl,checksum, andrequestId.GET /api/commands?deviceId=:idreturns active commands for device polling.- Add
scope=allto return active and terminal command history. POST /api/commands/:id/ackacknowledges a queued command.POST /api/commands/:id/progressaccepts numericprogressandstatus.
State machine:
queued -> acknowledged -> downloading -> installing -> success
\-> failed
Rules:
- Progress is between 0 and 100 and cannot regress.
- Success requires 100% and may only follow installing.
- Failed may only follow installing.
- Terminal commands cannot change.
- Identical retries return the existing command without adding audit entries.
- A device may have only one active OTA command.
requestIdis an optional idempotency key. Reuse with a different device or normalized OTA payload returns409 IDEMPOTENCY_KEY_REUSE.
GET /api/events/history?limit=40returns recent compact audit events.GET /api/eventsopens the SSE stream.
Emitted event types are device.updated, telemetry.updated, alert.created, alert.updated, command.created, and command.updated.
The server sends SSE comment heartbeats while connections are open. The MVP does not yet implement replay with Last-Event-ID.
POST /api/demo/inject-alert accepts an optional deviceId and injects a high-temperature telemetry reading. It exists only for the public demonstration workflow.