Skip to main content

Documentation Index

Fetch the complete documentation index at: https://dev.1st.app/llms.txt

Use this file to discover all available pages before exploring further.

Error envelope

Every error response uses the same envelope:
{
  "error": {
    "type": "invalid_request_error",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded: 600 requests per 10 minutes per key. Wait `Retry-After` seconds and retry. For higher throughput, use the bulk export endpoint instead of looping per-sensor.",
    "param": null,
    "doc_url": "https://docs.1st.app/errors/rate_limit_exceeded",
    "request_id": "req_1a2b3c4d5e6f7a8b"
  }
}
Branch on code, not on message. Messages are tuned over time for clarity; codes are a stable contract. The message field contains the FIX inline — written so an AI agent reading just the response body can self-correct. Lean on this. The request_id is also returned in the X-Request-Id header on every response (including 2xx). Share it with support if you need help.

Status code summary

HTTPWhen
400Validation failed (cursor, time range, body).
401Auth failed (missing / invalid / revoked / expired key).
403Key lacks the required scope (PATCH without read_write).
404Sensor not in your team or doesn’t exist.
413CSV result exceeds 250,000 rows — narrow the range or sensor list.
422Idempotency-Key reused with a different request body.
429Rate limit exceeded (see Retry-After).
500Backend hiccup. Retry with backoff.

Code reference

Each entry expands to a short fix; click through for the full page.
No Authorization header on the request. Fix: add Authorization: Bearer 1st_sk_<key_id>.<secret>. Full page →
Header malformed, key prefix doesn’t match an active key, or wrong secret. Fix: re-copy the key from /integrations/api-keys. Full page →
The key was revoked. Fix: mint a new one. Full page →
The key passed its expires_at date. Fix: mint a new key, optionally with a longer expiry preset. Full page →
Read-scope key calling PATCH /v1/sensors/{id}. Fix: mint a new key with read_write scope. Full page →
600 requests per 10 minutes per key. Fix: wait Retry-After seconds. For bulk reads use GET /v1/readings.csv instead of looping per-sensor. Full page →
Pagination cursor is malformed or expired. Fix: drop the cursor parameter and start over. Full page →
Cursor was issued under a different team’s key. Fix: drop the cursor and start fresh under the current key. Full page →
Range exceeds 90 days. Fix: split into windows ≤90 days and concatenate. For bulk pulls use /v1/readings.csv. Full page →
from/to not strict ISO 8601 UTC, or to ≤ from. Fix: use 2026-05-11T00:00:00Z format, to after from. Full page →
Sensor with this id isn’t in your team (or doesn’t exist). Fix: list sensors via GET /v1/sensors first. Full page →
Generic input rejection. Also fires as 422 when an Idempotency-Key is reused with a different request body. Fix: check the param field for what was rejected. Full page →
Backend hiccup. Fix: retry with exponential backoff. Share the request_id with support if it persists. Full page →