Errors and rate limits
Status codes, error bodies, and request limits.
When something goes wrong, the API returns a JSON body and an HTTP status code.
Error shape
{
"success": false,
"error": "Not a member of this workspace"
}Some service errors also include a message field. Prefer reading error first.
Status codes
| Status | Meaning |
|---|---|
| 400 | Bad input or a business rule failed (validation, wrong status) |
| 401 | Missing or invalid bearer token |
| 403 | Authenticated, but not allowed (role, scope, suspended, wrong workspace) |
| 404 | Resource not found or not visible to you |
| 409 | Conflict (for example workspace slug already taken) |
| 413 | Body too large (for example audio for transcription) |
| 429 | Rate limited, or X monthly posting cap reached |
| 500 | Unexpected server error |
| 503 | A dependency is not configured (for example speech-to-text) |
Rate limits
| Scope | Limit |
|---|---|
General /api/* |
About 100 requests per minute per authenticated user, or trusted client IP |
Auth (/api/auth/*) |
About 20 requests per 15 minutes per trusted client IP |
CLI device login (/api/cli/auth/*) |
About 30 requests per 15 minutes per trusted client IP |
AI routes (/api/ai/*) |
About 20 requests per minute |
Client IP comes from trusted proxy headers only (cf-connecting-ip, then x-real-ip, then the right-most x-forwarded-for hop). QStash/Workflow worker paths skip the global bucket and still require signature verification.
When limited, expect 429 and X-RateLimit-* headers. Back off and retry.
Platform caps
Scheduling or publishing to X can return 429 when the workspace hits its monthly X posting cap. Check usage with GET /api/posts/x-cap-usage before a large batch.
Tips
- Retry 429 and occasional 500 with exponential backoff.
- Do not retry 401 or 403 without fixing auth or permissions.
- For validation failures, the
errorstring usually names the field or rule.