Skip to main content

Error response format

Most errors carry success: false and a message that says what went wrong:
Most validation messages start with the field they are about (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

The x-api-key header is missing, or the key is wrong or deleted.
Check the header name (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 by code / errorCode. None of them creates a project or charges anything. See Credits and your own keys for how the two modes work.
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.
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.
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 answers 200 can still fail later, while generating or rendering. You find out in two ways:
  • Polling: GET /v1/project/{projectId} shows status: "failed" (or video.status: "FAILED"), with the reason in message.
  • Webhook: a payload with status: "FAILED". If the project failed before it had a video, data.videoId is null. Not every failure while generating sends this call yet, so keep polling as a backup. See Webhooks.
Credits charged for a failed project are refunded automatically. Whether to create it again is your call: check the message first, since an input problem will fail the same way twice.

Retrying safely

Never retry a create request without an Idempotency-Key. If the request timed out or answered a 5xx, the project may already exist and may already have been charged. Retrying without a key creates (and charges) a second one; retrying with the same key and body returns the first answer.
With an Idempotency-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:
  1. Send your own correlation id in metadata (for example { "jobId": "job_123" }).
  2. If a create fails with a 5xx or a network error, look for the project before retrying: GET /v1/video/list lists rendered videos, and the project appears in your dashboard. If you stored the projectId, call GET /v1/project/{projectId}.
  3. Only create again once you are sure the first attempt did not go through.
GET requests are safe to retry with backoff.

Handling errors in code

Debugging tips

  • Log the full response body of every non-2xx answer. The message usually 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 last message and progress.
  • Use GET /v1/health to 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 the projectId if you have one.

Next steps

Webhooks

Get notified when a project fails

Best Practices

Production-ready patterns