Skip to content
Log inGet an API key
Concepts

Errors

Errors use HTTP status codes and an application/problem+json body with a stable code. Match on code, not on the text of detail.

Error format

Every error body has type, title, status, detail, code and request_id (RFC 9457). Every response, error or not, carries an X-Request-Id header: quote it when you contact us.

An error response
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
X-Request-Id: req_8Zt3NwQ1pL5m

{
  "type": "https://zilapi.com/errors/insufficient_credit",
  "title": "Insufficient credit",
  "status": 402,
  "detail": "Available credit is below this job's cost.",
  "code": "insufficient_credit",
  "request_id": "req_8Zt3NwQ1pL5m"
}

Error codes

Error codes
StatusCodeMeaningWhat to do
422, 400invalid_requestA field is missing or has a bad value, the JSON is malformed, or a cursor is invalid. detail names the field, for example size_bytes: ….Correct the request. Retrying the same request will fail the same way.
401unauthorizedThe Authorization header is missing, or the key is unknown or revoked.Send Authorization: Bearer zil_live_… (or zil_test_…) with an active key from the dashboard.
402insufficient_creditYour available credit (unexpired credit minus what running jobs hold) is below this job's exact cost. Nothing started and nothing was charged.Add credit in the dashboard, or wait for running jobs to finish, then create the job again.
403forbiddenThis key or account is not allowed to do this.Check that you are using the right key and account.
403insufficient_scopeThe key lacks a scope this endpoint needs; detail names it (files:write, jobs:write, jobs:read or credits:read).Use a key that has the scope, or create one. See Authentication.
403account_suspendedThe account is suspended. New jobs are refused; jobs already running finish.Email support@zilapi.com.
403account_frozenThe account is frozen while a card payment dispute is open.Email support@zilapi.com to resolve the dispute.
404not_foundNo such file, job or model on this account in this mode. Test keys never see live objects, and live keys never see test ones.Check the id, and use a key of the same mode (live or test) that created the object.
405method_not_allowedThe path exists but not with this HTTP method.Check the method in the API reference.
409file_not_readyThe file is still uploading or validating, or it was rejected, so a job cannot use it yet.Poll GET /v1/files/{id} until status is ready. A rejected file never becomes ready.
409file_in_useYou tried to delete a file that a queued or processing job is using.Wait for the job to finish (or cancel it while it is queued), then delete the file.
409upload_expired/complete came after the upload window (6 hours from POST /v1/files) closed.Start a new upload with POST /v1/files.
409job_not_cancelableThe job has already started processing. Only queued jobs can be canceled.Let it finish. It is charged only if it succeeds.
409job_not_succeededYou asked for the output of a job that has not succeeded (yet).Poll GET /v1/jobs/{id} until status is succeeded. Failed and canceled jobs have no output.
409idempotency_key_reusedThis Idempotency-Key was already used with a different request body, or an earlier request with it did not record a result.Use a new key for each distinct request. Reuse a key only to retry the identical request.
410output_expiredThe result was deleted: outputs are kept for 7 days after the job succeeds.Download results within 7 days. To get it again, run a new job on a new upload.
413file_too_largeThe file is over 5 GB (5,368,709,120 bytes), over 25 MB for a test key, or over the model's size limit.Compress or split the audio. Use a live key for files over 25 MB.
413request_too_largeThe request body itself is too large. File bytes never go through the API; they go to the upload URL.Send file bytes to upload.url, not to the API.
415unsupported_media_typecontent_type is not an audio (or audio-in-video) type we accept.Send the file's real type, for example audio/wav, audio/mpeg, audio/mp4, audio/flac or audio/ogg.
422invalid_audioThe upload is not audio we can decode. The file becomes rejected (error.code on the file).Check the file plays locally and that content_type matches it, then upload it again.
422audio_too_longThe audio is longer than 6 hours (21,600 s), or longer than the model allows.Split the recording into parts under 6 hours.
422model_not_availableThe model id is unknown, not live, or has no price.Pick a model from GET /v1/models, or leave model out to use the task's default.
429rate_limitedOver the per-key limit: 120 creates or 1,200 reads per minute (and per IP for public endpoints).Wait Retry-After seconds, then retry. See Rate limits.
429quota_exceededAn upload quota was reached: 10 open uploads, retained input bytes, or validations per hour. Retry-After comes with the hourly limit.Finish or delete open uploads, delete files you no longer need, or wait Retry-After seconds.
500internal_errorSomething went wrong on our side. On a job, error.code is internal_error and you are not charged.Retry with the same Idempotency-Key. If it keeps happening, email us the request_id.
502provider_errorAn upstream service failed: the GPU provider (as a failed job's error.code) or the payment provider.Create the job again. Failed jobs are never charged.
503service_unavailableA dependency (storage, the rate-limit store) is briefly unavailable.Retry after Retry-After seconds, with the same Idempotency-Key for creates.

Handling errors

  • Retry 429, 500, 502 and 503 after Retry-After seconds (or with exponential backoff when there is none). For a POST, retry with the same Idempotency-Key.
  • Do not retry other 4xx errors unchanged: fix the request first. The exception is 409 file_not_ready: wait until the file is ready.
  • Only a succeeded job is ever charged. A failed request or a failed job costs nothing.
Retry on 429 and 503 with Retry-After
# --retry honours Retry-After on 429 and 503
curl -s --retry 5 --retry-max-time 120 https://api.zilapi.com/v1/jobs/$JOB_ID -H "Authorization: Bearer $ZILAPI_KEY" -D headers.txt
grep -i '^ratelimit-' headers.txt   # RateLimit-Limit: 1200, RateLimit-Remaining: 1199, RateLimit-Reset: 1