Errors
Status codes and the error response shape.
Errors use conventional status codes and a consistent JSON body:
{
"message": "Project not found",
"status": 404,
"timestamp": "2026-07-25T10:32:04.512Z",
"path": "/v1/projects/8f14e45f-.../calls"
}message is meant to be readable — surface it in logs rather than inventing your own text.
Status codes
| Code | What it means | What to do |
|---|---|---|
400 | Malformed request — bad JSON, unsupported audio format, file too large, empty file | Fix the request; retrying won't help |
401 | Missing, malformed, expired, deactivated, or deleted key — or an endpoint keys can't use | Check the key and that the endpoint is part of the public API |
402 | The organization's audio allowance is exhausted | Top up or change plan; retry after that |
403 | Authenticated, but not allowed to do this | Don't retry |
404 | The resource doesn't exist, or the key's organization can't see it | Check the id and the project |
409 | Duplicate upload — same audio already exists in this project | Continue with existingJobId |
429 | Rate limited | Back off; honour Retry-After |
5xx | Something failed on our side | Retry with backoff |
Two cases worth special handling
404 instead of 403 on other organizations' data. Asking for a project the key can't reach
returns 404, not 403 — ids can't be probed for existence. If you get an unexpected 404, check
whether the id belongs to the key's organization.
409 on upload is usually good news. It means the audio is already there and you weren't charged
twice. See duplicate uploads.
Retrying
Retry 429 and 5xx with exponential backoff. Don't retry 400, 401, 403, or 404 — the
result won't change. 402 is retryable, but only after topping up.
Uploads are content-hash de-duplicated, so replaying an upload after a network timeout won't create a duplicate call or a second charge.