Error response format
Most errors carrysuccess: false and a message that says what went wrong:
script, media, scenes.0.avatarId…), so you can show them to a developer as they are. A few checks that run before the schema answer without a field prefix (Invalid JSON body, Media type is required).
Authentication, entitlement and billing errors also carry a machine-readable code and/or errorCode. Branch on those, not on the message text.
HTTP status codes
Rate limits (429)
Limits are per team: every API key of a team shares them.
The minute is a fixed window that starts on the minute. A request over a limit is refused before anything runs, so nothing is created or charged and you can send it again as it is.
When too many of your URLs are downloading at once (a media import keeps its slot until the file is in your library), the message is
Too many downloads in progress, retry shortly, with Retry-After: 5 and no X-RateLimit-* headers.
Wait Retry-After seconds and send the request again. For batches, keep a few requests in flight instead of sending them all at once (see Bulk Generation).
Authentication errors
401 Not authenticated
Thex-api-key header is missing, or the key is wrong or deleted.
x-api-key) and the key in Settings → Developer API.
403 Entitlement required
The key is valid, but its team does not have access to the Hooked app.Billing errors (402)
All three share the status code. Tell them apart bycode / errorCode. None of them creates a project or charges anything. See Credits and your own keys for how the two modes work.
subscription_required
subscription_required
A managed team (one that uses Hooked’s provider keys) without an active subscription.Subscribe in billing, or switch the team to its own keys in Settings → AI keys.
INSUFFICIENT_CREDITS
INSUFFICIENT_CREDITS
A managed team without enough credits for this project.A team with no credits left at all is stopped before the project is priced: the message is then
Not enough credits to perform this action and creditsNeeded is 0. Buy a credit pack in billing.missing_credentials
missing_credentials
A byok team (bring your own keys) that has not added a provider key this request needs.Add the keys listed in
missingProviders (openrouter, elevenlabs, gemini or bria for the create endpoints) in Settings → AI keys. Which format needs which key is in the introduction.Validation errors (400)
The message names the field and the reason. Some you will see:
Ids in a request must belong to your team. A custom avatar, cloned voice or media file from another team is answered as not found.
Not found (404)
GET /v1/project/{id} (Project not found) and GET /v1/video/{id} (Video not found) answer 404 both when the id does not exist and when it belongs to another team.
Processing failures
A create call that answers200 can still fail later, while generating or rendering. You find out in two ways:
- Polling:
GET /v1/project/{projectId}showsstatus: "failed"(orvideo.status: "FAILED"), with the reason inmessage. - Webhook: a payload with
status: "FAILED". If the project failed before it had a video,data.videoIdisnull. Not every failure while generating sends this call yet, so keep polling as a backup. See Webhooks.
message first, since an input problem will fail the same way twice.
Retrying safely
With anIdempotency-Key header, a create (or any other POST that charges) can be retried with backoff like a GET: the same key with the same body within 24 hours answers with the first response and the header Idempotent-Replayed: true. The same key with a different body answers 422, and while the first request is still running, 409. See Idempotency.
Without a key:
- Send your own correlation id in
metadata(for example{ "jobId": "job_123" }). - If a create fails with a 5xx or a network error, look for the project before retrying:
GET /v1/video/listlists rendered videos, and the project appears in your dashboard. If you stored theprojectId, callGET /v1/project/{projectId}. - Only create again once you are sure the first attempt did not go through.
Handling errors in code
Debugging tips
- Log the full response body of every non-2xx answer. The
messageusually says exactly what to change. - Check ids by listing them first (
/v1/avatar/list,/v1/voice/list,/v1/music/list). - For a project that failed while generating,
GET /v1/project/{projectId}shows the lastmessageandprogress. - Use
GET /v1/healthto check whether the API is up. It needs no key.
Getting help
If an error does not make sense, email support@hooked.so with the endpoint, the request body (without your API key), the full response and theprojectId if you have one.
Next steps
Webhooks
Get notified when a project fails
Best Practices
Production-ready patterns