Skip to main content

Errors & limits

Error envelope​

Every error response has the same shape:

{
"error": "INVALID_REQUEST",
"message": "Human-readable explanation",
"statusCode": 400
}
  • error - a stable, machine-readable code (switch on this).
  • message - a human-readable explanation (don't parse this).
  • statusCode - matches the HTTP status.

Error codes​

CodeHTTPMeaning
INVALID_REQUEST400Body failed validation, or a precondition is unmet (e.g. no vector store configured).
UNAUTHORIZED401Missing, malformed, or revoked API key.
PAYMENT_REQUIRED402Insufficient credit balance, or a card was declined.
FORBIDDEN403The key is missing the required scope.
ACCOUNT_TERMINATED403The account has been terminated.
NOT_FOUND404The resource doesn't exist (e.g. no vector store configured).
RATE_LIMITED429You exceeded your request rate.
TOO_MANY_ACTIVE_JOBS429Your account already has as many unfinished jobs as it may. Wait for some to finish.
CAPACITY_EXCEEDED503The capacity behind this endpoint cannot start your job in time. Retry after Retry-After.
SERVICE_UNAVAILABLE503A downstream dependency (model provider, vector store) failed transiently. Retry with backoff.
Failed requests are never billed

If generation fails, the request isn't charged. Up-front charges are refunded on failure, and usage-metered charges settle only on success.

Rate limiting​

Requests are rate-limited per account. Defaults:

  • 60 requests/minute, with a short per-second burst allowance (roughly one-tenth of the per-minute limit). Your account may be provisioned with a higher limit.
  • 600 job polls/minute (GET …/jobs/:id), counted separately: polling many jobs does not use up the requests your submissions need.

Exceeding a window returns 429 RATE_LIMITED. Back off and retry.

Capacity and queueing​

A job you submit is queued and runs when capacity is free: it waits in our queue, not in the engine's. Two limits protect that queue:

  • Unfinished jobs. An account may have up to 1,000 jobs queued or running at once (your account may be provisioned with a different limit). Past it, a new job returns 429 TOO_MANY_ACTIVE_JOBS until some of yours finish.
  • Wait time. When the jobs ahead of yours would keep it waiting too long, the request returns 503 CAPACITY_EXCEEDED instead of queueing a job you would wait on for a long time.

A refused job is not created and not charged. Both responses carry a Retry-After header, in seconds: retry after that long. A job that was accepted but then waited past our longest wait fails with error_code: "CAPACITY_TIMEOUT" and is refunded — see Jobs.

Retrying safely​

  • 429 and 503 are transient - retry with exponential backoff. When the response has a Retry-After header, wait at least that many seconds.
  • 400, 401, 403 are not transient - fix the request or the key; retrying won't help.
  • 402 means you're out of credit (or a card was declined) - top up in the dashboard before retrying.

Tracking a job​

Every endpoint that returns a job_id records a job you can look up afterwards, including failures. When a request errors out — or when you just want to reconcile what actually landed — use the Jobs API to fetch the job by id, list everything still in flight, or export a window to CSV. Failed jobs carry an error message and, where applicable, an error_code from the table above.