| Specification | The API publishes an OpenAPI 3.1 document at GET /api/openapi.json. The API Reference is generated from it, and clients can be generated from it. |
| Transport | HTTPS only. Request and response bodies are JSON. |
| Authentication | A per-device bearer API key, or a client certificate verified by the TLS-terminating proxy (mTLS). One key per device. A rotated key revokes the previous one. |
| Timestamps | Set by the server on arrival, in epoch milliseconds. Client timestamps are ignored. |
| Identifiers | Devices are UUIDs. Metrics are integer ids from a shared catalogue. |
| Idempotency | One reading per request. A repeated request stores a second reading; clients don’t retry a 2xx. |
| Rate limiting | 120 requests per 60 seconds per device credential. Over the limit, 429 with a retry-after header. |
| Errors | 401 for a missing or revoked credential, with { "error": "unauthorized", "reason": "..." }. 4xx errors aren’t retried by the client; 5xx and connection errors are retried with backoff. |
| Health | GET /healthz for liveness and GET /readyz for readiness, both unauthenticated. See Errors and Limits. |
| Live updates | A WebSocket message bus with exact-match topics, one topic per device and metric. |
| Webhooks | Outbound events are signed with a shared secret over the raw body, delivered with retries on a fixed schedule, and never sent to private or link-local addresses. See Webhooks. |