Error envelope
All API errors return a structured JSON envelope with three fields:| Field | Type | Description |
|---|---|---|
error | string | A human-readable description of the error. Suitable for display to developers. |
reason_code | string | A stable, machine-readable code for programmatic error handling. Will not change. |
request_id | string | A unique identifier for this request. Include this in support requests for debugging. |
HTTP status codes
| Status | Meaning | When returned |
|---|---|---|
| 400 | Bad Request | Invalid request body, missing required fields, malformed JSON |
| 401 | Unauthorized | Missing, invalid, or revoked API key |
| 403 | Forbidden | Valid key but insufficient permissions for this action |
| 404 | Not Found | Resource does not exist or is not owned by this customer |
| 409 | Conflict | Idempotency key reuse with different parameters, or state conflict |
| 422 | Unprocessable Entity | Request is well-formed but semantically invalid |
| 429 | Too Many Requests | Rate limit exceeded. Check Retry-After header. |
| 500 | Internal Server Error | Unexpected server error. Retry with backoff. |
| 503 | Service Unavailable | Service temporarily unavailable. Retry with backoff. |
Reason codes
Authentication errors
reason_code | HTTP | Description |
|---|---|---|
auth_error | 401 | Session has expired or is invalid |
invalid_credentials | 401 | Invalid email or password |
invalid_api_key | 401 | API key is missing, malformed, or not recognized |
api_key_revoked | 401 | API key has been revoked |
api_key_expired | 401 | API key has passed its expiration date |
account_suspended | 403 | Customer account has been suspended |
account_not_found | 404 | No account found for the given credentials |
Rate limiting
reason_code | HTTP | Description |
|---|---|---|
rate_limited | 429 | Too many requests. Check Retry-After header for wait time. |
API key errors
reason_code | HTTP | Description |
|---|---|---|
api_key_not_found | 404 | The specified API key does not exist |
api_key_limit_reached | 409 | Maximum number of API keys reached for this customer |
Run errors
reason_code | HTTP | Description |
|---|---|---|
run_not_found | 404 | The specified run does not exist or is not owned by you |
run_already_cancelled | 409 | The run has already been cancelled |
run_not_cancellable | 409 | The run is in a terminal state and cannot be cancelled |
run_not_awaiting_input | 409 | Signal sent to a run not in awaiting_input state |
invalid_signal_type | 400 | Signal type is not accepted for this awaiting_input prompt |
Validation errors
reason_code | HTTP | Description |
|---|---|---|
validation_error | 400 | Request body fails schema validation |
conflict | 409 | Resource state conflict (e.g., duplicate idempotency key with different params) |
General errors
reason_code | HTTP | Description |
|---|---|---|
not_found | 404 | The requested resource was not found |
internal_error | 500 | An unexpected server error occurred |
service_unavailable | 503 | The service is temporarily unavailable |
Handling errors programmatically
Usereason_code for programmatic error handling instead of parsing the error message string. The reason_code is stable and will not change between API versions.
Rate limiting details
When you receive a429 Too Many Requests response, the Retry-After header tells you how many seconds to wait:
- Implement exponential backoff with jitter for automated retries.
- Respect the
Retry-Aftervalue — do not retry before it expires. - If you consistently hit rate limits, consider reducing your request rate or contacting support for a limit increase.
Getting help
When contacting support about an API error, always include:- The
request_idfrom the error response. - The
reason_code. - The HTTP status code.
- The timestamp of the request.