All error responses follow a consistent JSON shape:
{
"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 |
404 is returned for cross-organisation access attempts as well as genuinely missing resources. This prevents enumeration of other organisations’ job IDs.
Rate limit errors — 429
Standard (single job):
{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded: minute limit reached",
"code": "RATE_001",
"retry_after": 60
}
Batch variant — includes jobs_requested:
{
"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.
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
{
"error": "insufficient_credits",
"message": "No credits remaining — contact your administrator",
"code": "PAY_001"
}
Contact your account administrator or email 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.
{ "status": "processing" }
Only call download endpoints once GET /jobs/{id} returns status: "complete".