Rate limits
Requests are limited per API key over a fixed 60-second window, with separate budgets for reads and writes. The limits protect the control plane only — they say nothing about how many orders can be processing at once.
The limits
| Bucket | Limit | Applies to |
|---|---|---|
| Reads | 300 requests / minute | GET endpoints (order state, lists, asset status). |
| Writes | 60 requests / minute | POST endpoints (orders, batches, key management). |
| Uploads | Burst of 200, refilling at 10 / second | Asset declaration and confirmation (2 calls per photo). |
Uploads use a token bucket rather than a window: an entire shoot's worth of upload calls passes at once (up to 100 photos), and sustained traffic drains at the refill rate — a denied upload retries within about a second. Limits are counted per key — two keys of the same workspace have independent budgets. A batch counts as one write regardless of its scene count, and streaming (SSE or WebSocket) is not rate limited — prefer it over tight polling loops.
Response headers
Every response carries the state of your window:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window. |
X-RateLimit-Remaining | Requests left before a 429. |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets. |
Handling 429
When the window is spent, the API answers 429 with a Retry-After header (in seconds) and the standard error envelope. Wait that long, then retry — no backoff guessing needed:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
{ "error": { "status": 429, "reason": "rate limit exceeded — slow down" } }