v0.2.0

API reference

One REST API for every room your Cymos can see: 65 operations, generated from the same contract as the SDK and CLI. Test keys read the simulator; live keys read your paired Cymos.

Base URL

The Cymo API is a REST API over HTTPS. Every operation lives under one base URL, and every path starts with /v1.

base URL
https://api.cymatics.tech

Authentication

Send your API key as a bearer token in the Authorization header. A key belongs to one project and one mode: cym_test_ keys read the simulator, cym_live_ keys read your paired Cymos. Every response says which in meta.livemode. Create keys in the dashboard.

header
Authorization: Bearer cym_test_…
terminal
curl "https://api.cymatics.tech/v1/rooms/room_bedroom" \
  -H "Authorization: Bearer $CYMO_API_KEY"

Optionally name your client, such as my-app/1.2.0. The SDK, CLI and MCP server set it for you, and request logs show it.

X-Cymo-Clientstring, up to 100 charactersheaderThe calling surface and version, such as sdk/0.3.0 or cli/0.2.0. Request logs group requests by its prefix: sdk, cli, mcp or dashboard, and other for anything else.

Response shape

Success responses are { data, meta }; lists add page. Errors are { error, meta }. Fields are snake_case with units in the name, such as heart_rate_bpm, and timestamps are ISO 8601 in UTC.

envelopes
// One resource
{ "data": { … }, "meta": { … } }

// A list
{ "data": [ … ], "page": { "has_more": true, "next_cursor": "…" }, "meta": { … } }

// An error
{ "error": { "code": "resource_not_found", "message": "…" }, "meta": { … } }

// meta, on every response and stream message
{
  "request_id": "req_01",
  "project_id": "proj_demo",
  "livemode": false,
  "generated_at": "2026-10-24T23:55:30.000Z"
}

Response codes

The API uses standard HTTP status codes: 2xx for success, 4xx for a problem with the request and 5xx for a problem on our side. Each error carries a stable error.code; branch on it, not on the message.

400invalid_arguments, invalid_scenario
401invalid_api_key, expired_api_key, revoked_api_key
403insufficient_scope, feature_not_entitled, mode_mismatch
404resource_not_found
409configuration_conflict, revision_conflict, idempotency_conflict
410replay_expired, data_expired
413invalid_arguments
422invalid_arguments
429rate_limit_exceeded, quota_exceeded
500internal_error
503live_unavailable, service_unavailable

Errors describes every code and whether to retry it.

Rate limits

Requests are limited per key in fixed one-minute windows, and to twice that across the project. Over the limit, the API answers 429 rate_limit_exceeded with a Retry-After. Authenticated responses carry your remaining budget:

RateLimit-LimitintegerheaderRequests per minute allowed for the key. On every authenticated response.
RateLimit-RemainingintegerheaderRequests left in this minute, for the key and its project, whichever is lower.
RateLimit-ResetintegerheaderSeconds until the one-minute window resets.
Retry-AfterintegerheaderSeconds to wait before retrying. Sent with rate_limit_exceeded and service_unavailable, never with quota_exceeded.

Pagination

Lists are cursor-paginated. They take limit (default 100, up to 1000) and cursor: pass page.next_cursor until page.has_more is false. A cursor that outlives its snapshot answers 410 data_expired; start again from the first page.

Idempotency

15 writes accept an Idempotency-Key header. Replays the first response for an identical request within the project and mode. Retrying with the same key can't act twice; reusing it for a different request answers 409 idempotency_conflict.

header
Idempotency-Key: 4f9c1d2e-8b3a-4c6d-9e7f-1a2b3c4d5e6f

Streaming

Stream room, Stream person answer with Server-Sent Events. Each message holds the same { data, meta } envelope as a JSON response; reconnect with Last-Event-ID to resume. See Streaming.

Scopes and modes

Each operation needs one scope on the key: devices:write, models:write, raw:read, results:read, rooms:write, simulation:write, webhooks:write. A key without it gets 403 insufficient_scope.

Every operation answers test and live keys at the same path with the same shapes. Test only marks the simulator controls, which live keys can never call. See Test and live mode.

Versioning

The version is in the path, /v1. This reference is generated from the Cymo API's OpenAPI document, version 0.2.0 at commit 3745fd2. The SDK, CLI and this page read the same definitions, so they can't disagree.

Operations