Error Response Format
| Field | Type | Always Present | Description |
|---|---|---|---|
error | string | Yes | Human-readable error description |
code | string | Yes | Machine-readable error code (see table below) |
details | object | No | Additional context (validation errors, etc.) |
requestId | string | Yes | Unique request ID for support/debugging |
Always include the
requestId when contacting support about an API error. It enables fast lookup
in the request logs.HTTP Status Codes
| Status | Code | Description |
|---|---|---|
400 | BAD_REQUEST | Invalid request body, missing required fields, or malformed JSON |
401 | UNAUTHORIZED | Missing or invalid authentication credentials |
403 | FORBIDDEN | Authenticated but insufficient permissions for this action |
404 | NOT_FOUND | Resource does not exist or is not accessible in your workspace |
405 | METHOD_NOT_ALLOWED | HTTP method not supported for this endpoint |
409 | CONFLICT | Resource conflict (e.g., duplicate entry) |
422 | UNPROCESSABLE_ENTITY | Request is syntactically valid but semantically incorrect |
429 | TOO_MANY_REQUESTS | Rate limit exceeded — wait and retry |
500 | INTERNAL_SERVER_ERROR | Unexpected server error — contact support if persistent |
502 | BAD_GATEWAY | Upstream service unavailable |
503 | SERVICE_UNAVAILABLE | Service temporarily unavailable — retry with exponential backoff |
504 | GATEWAY_TIMEOUT | Upstream service timeout |
Validation Errors
When a request fails validation (status400), the error field contains the validation details as a JSON string. The structure follows Zod’s flatten() format:
error field to extract per-field validation messages:
Common Error Scenarios
- Authentication
- Permissions
- Not Found
- Rate Limiting
401 — Missing tokenFix: Include a valid Fix: Refresh your session token and retry.
Authorization: Bearer <token> header or X-API-Key header.401 — Expired tokenError Handling Best Practices
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.ok) return response;
if (response.status === 429 || response.status >= 500) {
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise((r) => setTimeout(r, delay));
continue;
}
}
throw new Error(`API error: ${response.status}`);
}
}
Production vs Development
In production, the API returns generic error messages for500 errors to avoid leaking internal details: