Introduction
Error Handling
A consistent error envelope and HTTP status codes across the API.
The API uses conventional HTTP status codes and returns a consistent JSON error envelope so clients can handle failures programmatically.
Error envelope
Every error response has the same shape:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "A human-readable explanation of what went wrong.",
"details": [{ "path": "body.name", "message": "Required" }]
}
}| Field | Description |
|---|---|
error.code | A stable, machine-readable error code (see below). |
error.message | A human-readable description. Do not parse this. |
error.details | Optional. Field-level issues, present for validation errors. |
Branch on the HTTP status code and error.code — never on error.message.
Status codes
| Status | Meaning |
|---|---|
400 Bad Request | The request was malformed. |
401 Unauthorized | Authentication is missing or invalid. |
403 Forbidden | The token is valid but not permitted to do this. |
404 Not Found | The resource does not exist. |
409 Conflict | The request conflicts with the current state. |
422 Unprocessable Entity | The request was understood but could not be processed. |
429 Too Many Requests | You have been rate limited; retry later. |
500 Internal Server Error | An unexpected error occurred. |
502 Bad Gateway | An upstream provider returned an error. |
503 Service Unavailable / 504 Gateway Timeout | The service was unavailable or timed out. |
Error codes
| Code | Typical status |
|---|---|
VALIDATION_ERROR | 400 / 422 |
UNAUTHORIZED | 401 |
FORBIDDEN | 403 |
NOT_FOUND | 404 |
CONFLICT | 409 |
RATE_LIMITED | 429 |
INTERNAL_ERROR | 500 |
UPSTREAM_ERROR | 502 / 503 / 504 |
UPSTREAM_ERROR covers every upstream provider failure: a bad response
(502), an unavailable service (503), and a gateway timeout (504). Branch
on the HTTP status code when you need to tell these apart.