> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lyrcs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> HTTP status codes, error strings, and rate limit headers

All error responses follow a consistent JSON shape:

```json theme={null}
{
  "error": "validation_error",
  "message": "language field is required",
  "code": "VAL_001"
}
```

## Error reference

| HTTP | `error`                | `code`     | Trigger                                                                                                          |
| ---- | ---------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------- |
| 400  | `validation_error`     | `VAL_001`  | Missing required field, unsupported language, invalid `audio_url`, batch with 0 or >20 jobs, malformed JSON body |
| 401  | `unauthorized`         | `AUTH_001` | Missing or malformed `Authorization` header, invalid API key, inactive key, expired key                          |
| 402  | `insufficient_credits` | `PAY_001`  | Organisation credit balance is 0 or below — contact your administrator                                           |
| 403  | `forbidden`            | `AUTH_002` | API key does not have permission to access this endpoint — contact your account administrator                    |
| 404  | `not_found`            | `NOT_001`  | Job or batch not found; job belongs to a different organisation; unknown LRC/SRT type in download URL            |
| 429  | `rate_limit_exceeded`  | `RATE_001` | Any rate limit window exhausted                                                                                  |

<Note>
  404 is returned for cross-organisation access attempts as well as genuinely missing resources. This prevents enumeration of other organisations' job IDs.
</Note>

## Rate limit errors — 429

Standard (single job):

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded: minute limit reached",
  "code": "RATE_001",
  "retry_after": 60
}
```

Batch variant — includes `jobs_requested`:

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded: minute limit would be exceeded by this batch",
  "code": "RATE_001",
  "retry_after": 60,
  "jobs_requested": 15
}
```

The `retry_after` field is the number of seconds to wait before retrying. A `Retry-After` header with the same value is also included.

## Rate limit headers

Every authenticated response includes the current rate limit state:

| Header                         | Value                                    |
| ------------------------------ | ---------------------------------------- |
| `X-RateLimit-Limit-Minute`     | `10`                                     |
| `X-RateLimit-Limit-Hour`       | `100`                                    |
| `X-RateLimit-Limit-Day`        | `1000`                                   |
| `X-RateLimit-Remaining-Minute` | Requests remaining in the current minute |
| `X-RateLimit-Remaining-Hour`   | Requests remaining in the current hour   |
| `X-RateLimit-Remaining-Day`    | Requests remaining today                 |

Check `X-RateLimit-Remaining-Minute` before submitting a large batch to confirm you have enough headroom.

## Validation errors — 400

Common triggers for `VAL_001`:

* `language` field missing or not matching any entry in `GET /api/v1/languages` (case-sensitive)
* Neither `file` nor `audio_url` provided to `POST /transcribe`
* `audio_url` is not a valid HTTPS URL
* Batch body is not an array or `{ jobs: [...] }` object
* Batch `jobs` array has 0 or more than 20 entries
* Individual batch job missing `audio_url` or `language`
* Invalid audio MIME type or file extension on file upload

## 402 — Insufficient Credits

```json theme={null}
{
  "error": "insufficient_credits",
  "message": "No credits remaining — contact your administrator",
  "code": "PAY_001"
}
```

Contact your account administrator or email [support@lyrcs.ai](mailto:support@lyrcs.ai) to add credits.

## Download endpoints — 202 vs 404

The download endpoints (`/download/lrc/*`, `/download/srt/*`) return `202` rather than `404` when a job exists but alignment hasn't completed. This is intentional — `202` means "try again later", while `404` means the job doesn't exist.

```json theme={null}
{ "status": "processing" }
```

Only call download endpoints once `GET /jobs/{id}` returns `status: "complete"`.
