Errors
The API uses conventional HTTP status codes and returns a consistent JSON error envelope you can branch on programmatically.
Error envelope#
Every error response has a detail object with a stable code, a human-readable message, and optional details:
{
"detail": {
"code": "INSUFFICIENT_SCOPE",
"message": "This endpoint requires a read_write token.",
"details": { "token_scope": "read", "required": "read_write" }
}
}Status codes#
| Status | Meaning |
|---|---|
| 401 | Missing or invalid token. |
| 402 | Insufficient credits for a charged operation. |
| 403 | Authenticated, but the token's scope is insufficient. |
| 404 | The requested resource doesn't exist. |
| 422 | Request body or parameters failed validation. |
| 429 | Rate limit exceeded — back off and retry. |
Error codes#
The code values you may encounter:
| Code | Status | When |
|---|---|---|
MISSING_AUTH_HEADER | 401 | No Authorization header sent. |
INVALID_TOKEN_FORMAT | 401 | Header present but not a cornect_ bearer token. |
INVALID_TOKEN | 401 | Token not found or revoked. |
TOKEN_EXPIRED | 401 | Token is past its expiry date. |
TOKEN_NOT_WORKSPACE_BOUND | 401 | Legacy token with no workspace — mint a new one. |
NOT_WORKSPACE_MEMBER | 401 | Token owner was removed from the workspace. |
INSUFFICIENT_SCOPE | 403 | A read token called a read_write endpoint. |
insufficient_balance | 402 | Not enough credits to create the export. |
Handling errors in code#
Branch on detail.code rather than parsing messages. A robust handler distinguishes auth failures (fix the token), scope/credit failures (fix the request or top up), and 429 (retry with backoff):
async function call(url, init) {
const res = await fetch(url, init);
if (res.ok) return res.json();
const { detail } = await res.json().catch(() => ({ detail: {} }));
switch (detail.code) {
case "INVALID_TOKEN":
case "TOKEN_EXPIRED":
throw new Error("Auth failed — check your token");
case "INSUFFICIENT_SCOPE":
throw new Error("Use a read_write token");
case "insufficient_balance":
throw new Error("Out of credits — top up at /account/credits");
default:
if (res.status === 429) throw new Error("Rate limited — retry with backoff");
throw new Error(detail.message || `HTTP ${res.status}`);
}
}For deeper retry/idempotency guidance see the Error Handling guide.