Error Codes
Reference for API error codes and how to resolve them.
Error Response Format
Errors return a flat JSON envelope:
{
"error": "invalid_input",
"detail": "Human readable description of what went wrong",
"request_id": "b3c1e2f0-2a4d-4a1e-9c3f-0f2b7c1d5e6a"
}| Field | Description |
|---|---|
error | Stable, machine-readable code (see below) |
detail | Human-readable description of the failure |
request_id | Correlation id, also echoed on the x-request-id response header |
hint | Optional actionable next step (present on some errors) |
docs | Optional link to relevant documentation (present on some errors) |
HTTP Status Codes
| Status | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Missing or invalid authentication |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource does not exist |
| 409 | Conflict - Idempotency-Key reused or request already in progress |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error |
Error Codes
The API uses a short set of stable, lowercase codes in the error field. Some routes add a more specific code (for example WALLET_NOT_CONFIGURED on execution routes); those are documented alongside the endpoint that raises them.
| Code | HTTP status | Meaning | Resolution |
|---|---|---|---|
unauthorized | 401 | Missing or invalid authentication | Include a valid session cookie or API key |
insufficient_scope | 403 | The session or key lacks the required scope | Use a key with the needed scope |
invalid_input | 400 | Request validation failed | Check required fields and formats |
not_found | 404 | Resource does not exist or is not visible to you | Verify the resource id |
conflict | 409 | Request conflicts with the current state | Reconcile and retry |
rate_limited | 429 | Too many requests | Back off and retry (see rate-limit headers below) |
internal_error | 500 | Unexpected server error | Retry with backoff; contact support if it persists |
Idempotency Errors
| Code | Description | Resolution |
|---|---|---|
idempotency_conflict | The Idempotency-Key was reused with a different request body. Response includes originalExecutionId. | Use a new key for a different request |
idempotency_in_progress | A request with this Idempotency-Key is still being processed | Retry shortly |
See Direct Execution for the full idempotency policy.
Workflow run failures
Failures that occur while a workflow run executes, rather than while handling an API request, are surfaced in the run logs with a separate stable code of the form PREFIX-NNNN (for example E-0001 for a run timeout). See Run Error Codes for the full list.
Rate Limiting
A rate_limited error (HTTP 429) means you have exceeded the request budget for the endpoint. Back off and retry using the rate-limit headers below.
Rate-limit headers
Every response from a rate-limited endpoint (both success and 429) carries the current limiter state, so clients can pace requests instead of guessing:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window |
X-RateLimit-Remaining | Requests left in the current window |
X-RateLimit-Reset | Unix epoch (seconds) when the window frees a slot |
Retry-After | Seconds to wait before retrying (sent only on 429) |
Status and long-poll endpoints additionally return X-Poll-Interval-Hint: the server-recommended number of seconds to wait before polling again. A value of 0 means the resource has reached a terminal state and no further polling is needed.
Anti-abuse endpoints (for example password reset and MFA enrollment) intentionally omit
X-RateLimit-Remainingso they don’t disclose a caller’s remaining attempt budget. They still sendRetry-Afteron429.
Retry Strategy
For transient errors (5xx, rate limits), use exponential backoff:
Wait time = min(base * 2^attempt, max_wait)Recommended:
- Base: 1 second
- Max attempts: 5
- Max wait: 30 seconds