Errors & Rate Limits
Error response shapes, codes, and per-tier limits.
Error shape
Every REST error response is JSON:
{
"success": false,
"error": "Human-readable message",
"code": "MACHINE_READABLE_CODE"
}Codes
| HTTP status | code | Meaning |
|---|---|---|
400 | VALIDATION_ERROR | Request body/query failed schema validation |
401 | UNAUTHORIZED | Missing, malformed, invalid, revoked, or expired API key |
402 | PAYMENT_REQUIRED | Out of credits — response includes an upgrade_url |
404 | NOT_FOUND | Decision or job doesn't exist, or isn't owned by your account |
429 | RATE_LIMITED | Rate limit exceeded — response includes retryAfter (seconds) |
Rate limits
Per API key, tier-based, checked on every request (burst + daily):
| Tier | Burst | Daily |
|---|---|---|
| Free | 60 req/min | 1,000 req/day |
| Pro / Beta | 300 req/min | 10,000 req/day |
| Admin | Unlimited | Unlimited |
A 429 response looks like:
{
"success": false,
"error": "Rate limit exceeded",
"code": "RATE_LIMITED",
"retryAfter": 12
}MCP note: the MCP server enforces the identical limits, but its transport (withMcpAuth) can only signal auth success or failure — a rate-limited MCP call currently surfaces as a generic connection/auth rejection, not a distinct rate-limit error with a retry hint. If you're hitting unexpected auth failures on MCP under heavy use, check whether you're rate-limited before assuming your key is invalid.
Idempotency and retries
If you're retrying a request that may have timed out, set the same Idempotency-Key header on the retry (POST requests only). A repeated key within 24 hours replays the original response instead of re-running the work or re-charging credits.