Errors
The error envelope, what each status means, and what to do about it.
The envelope
Every error from the main API is the same shape, and it has exactly one field:
{
"error": "question is required"
} Status codes
| Status | Means | Do |
|---|---|---|
400 | The body failed validation. error names the field. | Fix the request. Retrying will not help. |
401 | Missing, revoked, or wrong-environment credential. | Check the key and that its environment matches the host. |
402 | A plan limit was reached. | Upgrade, or wait for the monthly counter to reset. |
403 | Authenticated but not allowed: role, plan, origin, or IP. | See CORS & origins and roles. |
404 | No such resource in this workspace. | Often a key from the wrong workspace rather than a missing row. |
409 | The resource is in a state that forbids this. | Read error and re-plan. |
429 | Rate limited. | Back off. See rate limits. |
500 | Something broke on our side. | Retry with backoff; report it if it persists. |
503 | A dependency is unavailable, or the feature is off in this environment. | Retry with backoff. |
404 versus 403
A resource that exists in another workspace returns 404, not 403. That is deliberate — 403 would confirm the id exists — so treat a surprising 404 as a possible credential problem rather than a missing record.
Handling it
const res = await fetch(url, init);
if (!res.ok) {
// One field. Always.
const { error } = (await res.json()) as { error: string };
if (res.status === 429) return retryWithBackoff();
if (res.status === 402) return showUpgradePrompt();
throw new Error(`oprag ${res.status}: ${error}`);
} Ready to ship?
Get started free