# Errors

> Curriculo API error formats and HTTP status codes, from 400 to 504, with what each means and what to do. Failed requests are never billed.

**Source:** /docs/errors/ (Curriculo Docs)  
**Updated:** 12 October 2026  
**Contact:** hello@curriculo.me

Errors are JSON and carry the HTTP status that matters. Nothing fails silently: a rejected request tells you why. Every response carries an `X-Curriculo-Request-Id` header; quote it when you contact us.

## Error formats

Rejections at the edge (authentication, credit, rate limit, oversized request) return:

```json
{"success": false, "error": "...", "message": "..."}
```

Errors raised while processing return:

```json
{"detail": "..."}
```

In a list request, a failed item carries its own error inside `results`, and the HTTP status of the request stays `200`. See [Batching](/docs/batching/).

## HTTP status codes

| Status | Meaning | What to do |
|---|---|---|
| `400` | The input is unusable: empty file, blank text, unreadable or password-protected document, malformed `job_details`, a duplicate JSON key. For a recording task, not enough credit to reserve the 2-hour maximum. | Fix the payload, or add credit. Retrying identical bytes will fail identically. |
| `401` | "Missing API token…", "Invalid API token." (unknown or revoked key), "API token expired.", or "Unknown API endpoint" for a path under `/public/` that does not exist. | Check the `Authorization` header, the key, and the path. |
| `403` | The key is valid but the account cannot serve traffic: no prepaid credit ("…Buy credits in the Console."), the account is suspended, or "Account provisioning incomplete". | Add credit in **Console → Billing**, or wait for provisioning to finish. If the account is suspended, contact us. |
| `404` | Unknown `job_id`, or one registered by a different account. Also an unknown task id, or a path outside `/public/`. | Register the job again; ids are scoped to the credential that created them. Check the base URL. |
| `413` | Over a size ceiling: request body, document, recording, batch length, or character count. | Split the workload, or send recordings by link. See [request size limits](/docs/requests-and-responses/#request-size-limits). |
| `422` | Schema validation failed: a required field is missing or misnamed. Also a translation language outside the 85 supported codes. | Compare against the [OpenAPI spec](https://api.curriculo.me/public/openapi.json). Field names are case-sensitive. See [Languages](/docs/languages/). |
| `429` | Rate limit exceeded. | Back off and retry. Honour `Retry-After` when present. |
| `500` | Our failure. | Retry once. If it persists, contact us with the `X-Curriculo-Request-Id`. |
| `503` | A dependency is unavailable, or a feature is not enabled here (for example media transcription). | Retry with backoff. |
| `504` | Processing exceeded the 300-second ceiling. | Send fewer items or a smaller document, or use the [async lane](/docs/background-processing/). |

> [!NOTE]
> Failed requests are never charged. A `4xx` or `5xx` costs you nothing, and neither does a failed background task.

## Retry guidance

- **Do not retry** `400`, `401`, `403`, `404`, `413` or `422` unchanged. Fix the request first.
- **Retry with backoff** on `429` and `503`.
- **Retry once** on `500`.
- **On `504`,** resend with fewer items or a smaller document. In a list request, resubmit only the items that returned a `504` entry.
- Re-sending a single failed document is always safe. It cannot create duplicates or half-finished records.

## Contact

Write to [hello@curriculo.me](mailto:hello@curriculo.me) with the time, the operation and the `X-Curriculo-Request-Id`.
