Errors
Every error response uses a consistent envelope:
{ "error": { "code": "BAD_REQUEST", "message": "source.url or source.upload_id is required", "details": null }}code— stable, machine-readable identifier (see catalog below)message— human-readable explanation, safe to surface to your usersdetails— optional, varies per error; usually the offending field
HTTP status codes
Section titled “HTTP status codes”| Status | When |
|---|---|
400 | Validation failed (missing field, wrong shape, invalid value) |
401 | Missing, invalid, or wrong-type credential |
404 | Resource doesn’t exist or doesn’t belong to your team |
429 | Rate limit exceeded — see Rate limits |
500 | Server error. Safe to retry with backoff. |
Canonical error codes
Section titled “Canonical error codes”| Code | HTTP | Meaning |
|---|---|---|
UNAUTHORIZED | 401 | Missing or invalid credential, or wrong credential type for this endpoint |
BAD_REQUEST | 400 | Request body or query parameter failed validation |
NOT_FOUND | 404 | The resource doesn’t exist on your team |
RATE_LIMITED | 429 | Too many requests in the current minute window |
INTERNAL_ERROR | 500 | Unhandled server error — automatically reported to us |
Idempotency
Section titled “Idempotency”The API doesn’t currently expose an Idempotency-Key header. The endpoints
most prone to accidental duplication — POST /v1/clips and POST /v1/clips/:id/renders
— are safe to retry on 5xx because:
/clipsallocates a freshjob_idon every call — duplicates produce separate jobs (you’d want to clean up extras manually)./clips/:id/rendersoverwrites the previous render output for the same clip — at most one render per clip exists, so retries are idempotent in practice.
Treat 4xx errors as final. Retry 5xx with exponential backoff.