Errors, rate limits & quotas
A single, predictable error shape and clear limits across every endpoint.
Error model
Every error, on every endpoint, is returned as the same JSON envelope, so a failure is never confused with a success body (decks come back as text/html, lists as JSON):
{
"error": {
"code": "invalid_input",
"message": "order must list every slide id exactly once."
}
}
Status codes
| HTTP | code | Meaning |
|---|---|---|
| 400 | bad_request | Malformed request: missing path param, unparseable JSON, wrong field type. |
| 400 | invalid_input | Well-formed but invalid arguments (e.g. a bad reorder permutation). |
| 401 | unauthorized | Missing, unknown, or revoked API key. |
| 404 | not_found | Unknown deck, slide, or brand id. |
| 409 | last_profile | Attempted to delete the only remaining brand profile. |
| 422 | invalid_html | HTML failed the canonical round-trip / layout contract. |
| 429 | rate_limited | Per-tenant request rate exceeded. |
| 429 | quota_exceeded | Monthly token allowance exhausted. |
| 500 | engine_error | Unexpected engine exception. |
Handle errors by reading error.code (stable, machine-readable) rather than parsing error.message (human-readable, may change).
Rate limits
The agent doors (/v1 and /mcp) are rate-limited per tenant with a fixed window:
| Scope | Limit | Window |
|---|---|---|
| Per tenant (REST + MCP) | 60 requests | 60 seconds |
When you exceed it you get 429 with these headers:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
{
"error": {
"code": "rate_limited",
"message": "Tenant rate limit exceeded (60 requests per 60000 ms)."
}
}
Back off until Retry-After (whole seconds) elapses. Watch X-RateLimit-Remaining to pace yourself proactively.
Monthly token quota
AI generation and editing consume tokens against a monthly allowance (input + output combined), tracked per user and reset at the start of each calendar month. The default allowance is 2,000,000 tokens; your plan and remaining balance are shown in Account → Usage. When the allowance is exhausted:
HTTP/1.1 429 Too Many Requests
{
"error": {
"code": "quota_exceeded",
"message": "Monthly usage quota exceeded. Your token allowance resets at the start of next month."
}
}