Skip to content

Rate limits and errors

Errors

Every error has the same shape, and code is stable (the message is meant for people and may change):

{"error": {"code": "missing_scope", "message": "Esta clave no tiene el alcance «ptz».", "status": 403,
           "request_id": "9b1c…", "required_scope": "ptz"}}

Messages are in Spanish; build your logic on code. A validation error includes fields ({"name": ["El campo nombre es obligatorio."]}), a 429 includes retry_after (and the Retry-After header), and a clash with a control lease includes lease (who holds it and until when). Every response, successful or not, carries X-Request-Id.

Status code What to do
400 key_in_query The key goes in the header. Rotate it: it ended up in logs
401 invalid_key, key_revoked, key_expired, creator_suspended, key_inactive Create a new key, or reactivate its creator
403 missing_scope The key needs the scope named in required_scope
403 forbidden, space_suspended The role is not enough, or the space is suspended
404 not_found It doesn't exist or this key can't see it: deliberately the same answer
409 conflict, camera_refused The camera can't do it right now (offline, another feature prevents it)
409 camera_leased Another key holds control of the camera
409 lease_held You tried to take or release a lease held by another key
409 lease_hold_limit Your key held that camera for 30 minutes in a row: wait retry_after seconds
409 lease_revoked_by_user A person released the camera from the panel: your key can't take it for retry_after seconds
409 kill_switch, automation_inactive, not_started, automation_refused The automation can't run or change right now
410 gone The camera is being decommissioned
422 validation_failed, no_manual_trigger Invalid data (fields), or the automation has no Manual trigger
429 rate_limited, automation_capped Wait for Retry-After
5xx internal_error, upstream_error, unavailable Retry only what can't duplicate (see below)

Rate limits

What Limit
Requests per key Whatever was chosen when it was created: 1 to 600 per minute (120 by default)
Requests per IP address, before the key is checked 1200 per minute
PTZ (move and stop) 400 per minute per person, like the panel's pad
Live video and talk 30 per minute per person
File links (snapshots and recordings) 240 per minute
Camera commands 60 per minute per person
Camera provisioning 10 per hour per space; credential rotation, 6
Control lease (take, renew, release, check) 60 per minute per key
Running automations 30 per minute per key, plus the engine's own caps: 12 runs per minute and 3 open at once per automation (automation_capped)
Testing the bucket and pinging a webhook 10 per minute per key

Keys and panel sessions belonging to the same person share the per-person limits.

Retries

  • On a 429, wait for Retry-After and try again: the server did nothing.
  • On a 5xx or a dropped connection, retry only what can't duplicate: GET, PUT, DELETE, a POST with an Idempotency-Key, renewing a lease, turning an automation on or off. Don't blindly retry POST /automations/{id}/run: it could run twice.
  • The SDKs already behave this way, with exponential backoff (0.5 s, 1 s, 2 s… up to 8 s) plus some jitter.

Idempotency

POST /cameras and POST /webhooks accept an Idempotency-Key. Repeating a request with the same one (within 24 h, with the same API key) returns the same response with the Idempotent-Replayed: true header, without creating anything new. With a different body you get 422 idempotency_mismatch; if the first request is still running, 409 idempotency_in_progress. The SDKs set one on every creation call.

Pagination

Lists accept ?page= and ?per_page= (up to 100) and respond with {"data": [...], "meta": {"page": 1, "per_page": 25, "has_more": true}}. cameras.all(), automations.all() and paginate() walk every page for you.