Skip to main content

Error response format

All error responses follow this structure:
Branch on error_code, not by parsing message. Every public API response also includes an X-Request-Id header. Record that identifier with your error logs and include it when contacting support. Common stable values include:

Failed tasks

The codes above describe a request that failed. A request can also succeed — POST /api/v1/task returns 202, credits are held, the task is created — and the task fail later. Poll GET /api/v1/task/{task_id} and that failure arrives on the task itself:
One case is not a clean either/or: if the provider refuses the submit, we settle the task to failure, refund its credits, and also return 502 upstream_provider_error. So you can hold a 502 while a real, already-refunded failed task exists. That response body carries no task_id — if you need the task, list your recent tasks rather than re-creating one, or the retry pays twice for one intent.
The same rule applies: branch on error_code and retryable, not on error. error is prose and may be reworded at any time.
An over-length prompt currently reports itself twice, and the two disagree. Measured 2026-09-13: the model refuses a prompt over 5,000 characters (“please shorten it to 5000 characters or fewer”). We do not enforce that limit before submitting, so the refusal comes back from the provider — and on POST /api/v1/task it is currently classified as upstream_provider_error (which this table calls “usually true”), while polling the same task returns invalid_task_input / retryable: false.The task-level verdict is the correct one: the rejection is a length check, so the same text fails it again. Keep prompts under 5,000 characters and tags under 1,000. The create-path classification is a known defect on our side, being fixed; until it ships, do not let a 502 on create send you into a retry loop.
An error we have not classified reports upstream_provider_error with retryable: true. We never report invalid_task_input for an unrecognised failure — that would send you to debug a request that was fine.

Retrying correctly

retryable: false means the input must change. Retrying it unchanged consumes a credit hold and a provider round trip each time, and all but never clears — across 180 days, of 634 unchanged resubmissions after a moderation rejection we classify false, exactly one cleared:
Credits are refunded on every failure, whatever the code.

Error codes

400 — Bad Request

The request body is malformed or missing required fields. Common causes:
  • Missing model, task_type, or input in the request body
  • Unknown or unsupported task_type
  • Invalid input parameters for the selected task type

401 — Unauthorized

The API key is missing, invalid, or has been revoked. Common causes:
  • No x-api-key header in the request
  • API key does not exist or has been deleted
  • API key has been disabled

402 — Payment Required

Your account does not have enough available credits to cover the task cost. How to fix: Top up credits in your dashboard.

403 — Forbidden

The authenticated account is not currently allowed to create a task.

404 — Not Found

The requested resource does not exist. Common causes:
  • Invalid task ID
  • Task belongs to a different user

429 — Too Many Requests

You have exceeded the rate limit. How to fix: Wait for the duration in retry_after_seconds (or the Retry-After header) before retrying.

500 — Internal Server Error

An unexpected error occurred on the server. What to do: For read-only requests, retry after a short delay. For POST /api/v1/task, do not automatically submit the same task again when the result is unknown; the current endpoint does not yet accept an Idempotency-Key. If you already received a task_id, poll that task instead.

503 — Service Unavailable

A dependency this endpoint needs (our database) was temporarily unreachable, so the request was not processed and nothing was charged. This is not a problem with your API key — the same key keeps working once the dependency recovers. How to fix: Retry after the number of seconds in retry_after_seconds (or the Retry-After header). Read-only requests can be retried directly. For POST /api/v1/task a 503 means the task was never created, so resubmitting is safe.

502 — Bad Gateway

The upstream AI provider returned an error or is temporarily unavailable. What to do: If the provider failure is explicit, the failed task follows the normal refund path. For an uncertain network or gateway result from POST /api/v1/task, do not blindly create another task. If you already received a task_id, poll that task instead.

Handling errors

Always check the HTTP status code before parsing the body. Follow Retry-After for 429 and 503 responses — a 503 means a dependency of ours was down, not that your key is invalid. Exponential backoff is appropriate for safe/read-only requests. For POST /api/v1/task, an uncertain 5xx or network result should be treated as “create outcome unknown” rather than automatically submitted again. The API does not currently provide Idempotency-Key replay semantics.

Example error handling