Error Handling
The JARAI Partner API uses a consistent error envelope across all endpoints. This guide covers the envelope format, all error codes, retry strategies, and how to use correlation IDs for debugging.
Error Envelope
All non-2xx responses return a JSON body with this structure:
{
"error": "ERROR_CODE",
"message": "Human-readable description of the error.",
"retryAfterSeconds": 42
}
| Field | Type | Description |
|---|---|---|
error | string | Machine-readable error code (e.g. RATE_LIMIT_EXCEEDED). |
message | string | Human-readable explanation. |
retryAfterSeconds | integer or null | Present on 429 responses. Number of seconds to wait before retrying. |
Correlation IDs
Every API response includes an X-Correlation-Id header. Include this value when contacting JARAI support — it allows the operations team to trace your request through the system.
Global Errors
These errors can occur on any endpoint:
| Status | Error Code | Description |
|---|---|---|
| 401 | UNAUTHORIZED | API key is missing, invalid, or revoked. |
| 403 | PARTNER_NOT_ACTIVE | Partner account is not in Active status. |
| 403 | PERMISSION_DENIED | API key lacks the required scope for this endpoint. |
| 413 | — | Request body exceeds the size limit. |
| 429 | RATE_LIMIT_EXCEEDED | Request rate or daily quota exceeded. Includes retryAfterSeconds. |
| 500 | INTERNAL_ERROR | Unexpected server error. |
| 503 | SERVICE_UNAVAILABLE | System is temporarily unavailable for maintenance. |
Production Trigger Errors
POST /v1/accounts/{accountId}/productions
| Status | Error Code | Description | Retry? |
|---|---|---|---|
| 400 | INVALID_REQUEST | Missing required field or malformed JSON body. | No — fix request |
| 403 | INSUFFICIENT_SCOPE | accountId not in caller’s permitted accounts. | No |
| 403 | ACCOUNT_NOT_ACTIVE | Account status is not Active or Pilot. | No |
| 409 | BUDGET_GATE_1_FAILED | Account monthly AI spend ceiling exceeded. | No — wait for next month or top up |
| 409 | BUDGET_GATE_2_FAILED | Customer monthly AI spend ceiling exceeded. | No — wait for next month |
| 409 | CONCURRENCY_LIMIT_REACHED | Account or customer concurrent production ceiling reached. | Yes — wait for in-flight productions to finish |
| 409 | SENSITIVITY_RULE_SUPPRESSED | Content sensitivity rule suppressed this topic. | No — adjust topic |
| 422 | SUBJECT_OVERRIDE_MISSING | Content theme title template requires a subject override. | No — include subject |
Production Status Errors
GET /v1/productions/{productionId}, GET /v1/accounts/{accountId}/productions
| Status | Error Code | Description |
|---|---|---|
| 404 | NOT_FOUND | Production does not exist or is outside your permitted accounts. |
Cancellation Errors
DELETE /v1/productions/{productionId}
| Status | Error Code | Description |
|---|---|---|
| 403 | CANCELLATION_NOT_PERMITTED | Cannot cancel non-API-triggered productions. |
| 404 | NOT_FOUND | Production does not exist or is outside your permitted accounts. |
| 409 | ALREADY_TERMINAL | Production is already Published or Failed. |
| 409 | CANCEL_IN_PROGRESS | Another cancel request is already processing. Retry after a few seconds. |
Deliverable Errors
GET /v1/productions/{productionId}/deliverables
| Status | Error Code | Description |
|---|---|---|
| 404 | NOT_FOUND | Production does not exist or is outside your permitted accounts. |
Performance Errors
GET /v1/productions/{productionId}/performance
| Status | Error Code | Description |
|---|---|---|
| 404 | NOT_FOUND | Production does not exist or is outside your permitted accounts. |
| 409 | PERFORMANCE_DATA_NOT_READY | Production not yet Published; no performance data available. |
Account Query Errors
GET /v1/accounts, GET /v1/accounts/{accountId}, GET /v1/accounts/{accountId}/avatars, GET /v1/accounts/{accountId}/platforms
| Status | Error Code | Description |
|---|---|---|
| 404 | NOT_FOUND | Account does not exist or is outside your permitted accounts. |
Webhook Management Errors
POST/GET/DELETE /v1/webhooks*
| Status | Error Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST | eventTypes absent or empty. |
| 404 | NOT_FOUND | Subscription does not exist or belongs to a different partner. |
| 409 | SUBSCRIPTION_NOT_ACTIVE | Cannot ping a non-Active subscription. |
| 409 | SUBSCRIPTION_NOT_FAILED | Cannot reinstate a subscription that is not in Failed status. |
| 422 | HTTPS_REQUIRED | Endpoint URL scheme is not HTTPS. |
| 422 | INVALID_ENDPOINT_URL | Endpoint URL resolves to a private/localhost address or is malformed. |
| 422 | INVALID_EVENT_TYPE | Event type not in the valid vocabulary. |
Registration Errors
POST /v1/partners/register, GET /v1/partners/verify
| Status | Error Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST | Missing required field or invalid email format. |
| 400 | TOKEN_MISSING | Verification token query parameter absent. |
| 400 | TOKEN_INVALID | JWT signature invalid or malformed. |
| 400 | TOKEN_EXPIRED | JWT exceeded 24-hour validity window. |
| 409 | EMAIL_ALREADY_REGISTERED | A partner with this email already exists. |
| 409 | ALREADY_VERIFIED | Partner is already Active. |
| 429 | RATE_LIMIT_EXCEEDED | More than 5 registration attempts from this IP in 10 minutes. retryAfterSeconds: 600. |
Key Rotation Errors
POST /v1/partners/keys/rotate
| Status | Error Code | Description |
|---|---|---|
| 403 | SELF_SERVE_ROTATION_DISABLED | Self-serve key rotation is disabled for your partner account. |
| 409 | NO_ACTIVE_KEY | No active API key exists for your partner. |
| 409 | ROTATION_IN_PROGRESS | A rotation is already in progress. Retry in a few seconds. |
Request History Errors
GET /v1/partner/requests
| Status | Error Code | Description |
|---|---|---|
| 400 | INVALID_LIMIT | limit parameter outside 1–100 range. |
| 422 | DATE_RANGE_TOO_WIDE | from/to window exceeds 30 days. |
| 422 | INVALID_DATE_FORMAT | from or to is not a valid ISO 8601 datetime. |
| 422 | INVALID_STATUS_CLASS | status parameter is not 2, 4, or 5. |
Usage Analytics Errors
GET /v1/partner/usage
| Status | Error Code | Description |
|---|---|---|
| 422 | INVALID_MONTHS_PARAM | months parameter outside 1–12 range. |
Retry Strategy
When you receive a retryable error, follow these guidelines:
- 429 responses: always respect
retryAfterSeconds. Do not retry before the indicated time. - 5xx responses: retry once after 5 seconds with exponential backoff. If the second attempt also fails, wait 30 seconds before a third attempt.
- 409 CONCURRENCY_LIMIT_REACHED: wait for an in-flight production to complete (poll or use webhooks), then retry.
- 409 CANCEL_IN_PROGRESS / ROTATION_IN_PROGRESS: retry after 5–10 seconds.
Do not retry 400, 403, or 422 errors — these indicate a client-side issue that requires a code or configuration change.
Next Steps
- Rate Limiting — understand rate limit tiers and response headers
- Production Lifecycle — production states and error codes in context
- Webhook Integration — real-time error notifications via webhooks