Public API
Errors
Error response format and API error codes.
Every non-2xx response uses this envelope. The request_id is also sent in the X-Request-Id response header; quote it when you contact support.
{
"error": {
"code": "insufficient_credits",
"message": "Organization balance cannot cover this job's minimum cost.",
"details": { "credits_required": 12, "credits_available": 3 },
"request_id": "req_5f1c2a3e8c1b4d6e9a532d1f"
}
}code is stable and meant for your code to branch on; message is for people and may change. details is present only when it adds something.
| Code | HTTP | Meaning | details |
|---|---|---|---|
unauthorized | 401 | Missing, malformed, revoked, expired or unknown key (indistinguishable on purpose). | — |
forbidden_scope | 403 | The key lacks the endpoint's scope. | required_scope |
not_found | 404 | Unknown job or webhook, or one that belongs to another organization or the other key mode. | — |
validation_failed | 400 | The request failed validation. Also 409 when a job cannot be cancelled or deleted in its current state, and 413 when the JSON body is over 1 MB. | 400: issues[] (path, message), or reason (e.g. multipart_not_started, too_many_endpoints). 409: reason (processing_cannot_be_cancelled, processing_cannot_be_deleted, already_terminal). 413: reason (body_too_large), max_bytes. |
insufficient_credits | 402 | Not enough credits to start the job. | credits_required, credits_available |
rate_limited | 429 | Per-key or per-IP limit reached. See Retry-After. | reason (key_rate_limited, ip_throttled), limit, reset |
idempotency_conflict | 422 | The same Idempotency-Key was used with a different body. Also 409 while the first request with that key is still running. | retry_after (409) |
unsupported_conversion | 400 | The format pair is disabled or unknown. | input_format, output_format |
file_too_large | 413 | The input exceeds your plan's limit. Also appears as a job's error.code when detected after the job was created. | max_bytes |
url_import_failed | 400 | An import/url URL is not allowed (not https, blocked address) when you create the job. Also a job's error.code when the fetch fails. | reason: blocked_address, not_https, invalid_url, too_many_redirects, http_status, network |
internal | 500 | Unexpected failure. A 503 with details.retryable: true means a dependency was briefly unavailable (the credit service, or file storage with reason: storage_unavailable); retry after Retry-After. | retryable, reason (storage_unavailable), or reason (system_error, timeout) on a job's error |
Errors on a job
A job that fails after it was accepted does not return an HTTP error; it has status: "error" and an error object with the same shape (code, message, optional details):
{
"id": "11111111-1111-4111-8111-111111111111",
"status": "error",
"error": {
"code": "url_import_failed",
"message": "The source file could not be imported.",
"details": { "reason": "http_status" }
}
}A failed job is never charged.
Retrying
Retry 5xx and 429 responses after a short delay (honour Retry-After). Use an Idempotency-Key when you retry POST /jobs so a retry cannot create a second job. Do not retry 4xx responses unchanged.