Errors
Every error response is JSON. Validation errors follow Laravel's standard format. Status codes are conventional.
All error responses are JSON. Validation errors follow Laravel’s standard format:
{
"message": "The output format field must be one of: png, jpg, jpeg, ...",
"errors": {
"output_format": [
"The output format field must be one of: png, jpg, jpeg, ..."
]
}
}
Status codes
| Status | When |
|---|---|
401 | Missing or unrecognized API key. |
403 | API key recognized but not authorized to act on the resource. |
404 | Task or job ID not found, or not visible to this API key. |
422 | Validation failure (bad format, missing field, invalid option value). |
429 | Rate limit exceeded (600/min/account). The Retry-After header gives the wait in seconds. |
5xx | Internal failure. Retry with exponential backoff. |
Processing errors (creation_failed)
A job lands in creation_failed when something went wrong producing the output: an unreachable URL, a bad input file, an unsupported codec combination, and so on. The API response for GET /convert/{id} and GET /jobs/{id} only reports the status; the underlying tool error (typically an ffmpeg, magick, or LibreOffice stderr message) is visible in the dashboard for that specific job.
Common causes:
- Bad inputs: corrupt or truncated source file.
- Unsupported codec combination: the output container can’t carry the input streams without re-encoding, and the chosen codec couldn’t produce a valid result.
- Unreachable URL (website capture only): the source URL returned 4xx/5xx or didn’t respond. If
http_success: truewas set on the request, any 4xx/5xx response forces this state. - Validation that snuck past the synchronous response: rare, but possible if an option only proves invalid mid-job.
Resubmit the same request after fixing the input. If the job consistently fails, check the dashboard log for that job ID, the underlying tool stderr is recorded there.
Delivery errors (delivery_failed)
delivery_failed indicates the conversion succeeded but the upload to your destination’s storage didn’t. Common causes:
- Storage credentials revoked or rotated.
- Bucket permissions changed.
- Destination misconfigured (e.g. region mismatch).
Check your destination configuration in the dashboard, then resubmit.
Rate limiting
When you hit 429, the response includes a Retry-After header with the recommended wait time in seconds. The simplest correct behaviour:
import time, requests
r = requests.post(url, auth=auth, files=...)
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After", 60)))
r = requests.post(url, auth=auth, files=...)
For high-volume use, implement a token bucket on your side at 10 requests per second (the per-minute average of the 600/min limit) and you won’t see 429s in normal operation.