AI video API error handling: retries, idempotency and recovery


Quick answer
Retry the operation that failed, without automatically creating a replacement video. Classify HTTP errors separately from project errors and uncertain transport outcomes. Save the returned project ID immediately and retry reads for that ID. If creation timed out before an ID arrived, reconcile first: a timeout or server error does not prove that no job was created, and an Idempotency-Key guarantee is not documented.
An AI video integration has more than one failure boundary: submitting a request, learning a project’s state, processing the media and retrieving an existing output. A single “retry everything” branch mixes those operations and can turn a temporary status-read failure into another generation. This guide owns error classification and recovery decisions, using Magic Hour’s current API contract and recovery documentation checked October 24, 2026.
Record the operation before deciding to retry
Keep an application request record before submission. Include your internal intent identifier, customer/account, exact endpoint, submitted values, asset references and request time. Once the create response arrives, save its id before handing work to a wait step or returning to the browser. Record whether a failure occurred before a response, on an HTTP response, or after a successful creation.
Failure boundary | What you know | Safe next decision |
|---|---|---|
Create request rejected with a documented 4xx body | There is a classified request problem. | Repair the specified input, authentication or account condition; do not repeat unchanged. |
Create timeout, connection loss or 500 before saving an ID | Acceptance may be uncertain. | Reconcile history and retained responses before authorizing another creation. |
GET fails after a project ID was saved | The read failed; generation state is unknown. | Retry or resume that same GET with a bounded policy. |
GET succeeds with status error | The existing project failed processing. | Read error.code/message, preserve inputs and decide on a corrected new attempt. |
Output retrieval fails after completion | An existing output may still be available. | Retry retrieval or obtain a current URL for the same project. |
Use the current HTTP error fields
Documented API error bodies contain code and message. Route decisions on the machine-readable code and HTTP status, while retaining a bounded message for diagnostics. Do not depend on an English substring such as “credits” to decide which account action to show. A non-JSON proxy error or a lost connection is a transport outcome, not an invented API error code.
HTTP status | Documented code | Recovery decision |
|---|---|---|
400 | invalid_request | Correct JSON syntax, missing fields or invalid schema values. |
401 | unauthorized | Repair the server-side API credential or authorization header. |
402 | insufficient_credits | Resolve the credit condition before another attempt. |
402 | subscription_required | Resolve required subscription access. |
402 | plan_upgrade_required | Choose permitted settings or resolve the plan requirement. |
404 | not_found | Check the exact route, identifier and account ownership. |
422 | unprocessable_entity | Change incompatible request values or asset references. |
500 | internal_server_error | For a read, retry within bounds; for creation, reconcile possible acceptance first. |
The three 402 codes have different meanings. They are not all a low-balance error. Likewise, a 404 on a project read should not be treated as proof that a previous creation failed: check the saved ID and which account’s key is making the read. Preserve unfamiliar codes and escalate them rather than silently treating every new code as retryable.
A concrete request and repair example
Use the current Image-to-Video API reference as the exact creation handoff. The route is POST https://api.magichour.ai/v1/image-to-video with Authorization: Bearer <api_key> and Content-Type: application/json. Keep the real key on your server.
An illustrative body is {"name":"Approved product shot","end_seconds":5,"model":"kling-3.0","resolution":"720p","audio":false,"assets":{"image_file_path":"api-assets/your-account/approved-product.png"},"style":{"prompt":"A slow camera push toward the product on a stationary table."}}. Replace the asset placeholder with a real uploaded file_path or a permitted direct file URL and confirm model/settings access for the account. This is a schema illustration, not a submitted generation or output-quality claim.
The create response includes id and credits_charged; the live OpenAPI also retains deprecated estimated_frame_cost. Read the current fields rather than inferring completion or final cost from the response alone. A returned id identifies the project to recover. It is not evidence that the output has already passed review or that a file was saved.
Suppose the caller instead sends end_seconds as the string "five". The published request schema expects a number; a validation failure should lead to correcting the field before another submission. For incompatible model, duration, resolution, audio or end-frame values, inspect the actual HTTP status, code and message rather than guessing which validation layer rejected the request. The Image-to-Video reference documents invalid_request at 400 and unprocessable_entity at 422. Its broad schema range is not permission to use every duration with every model.
Asset mistakes also need a repair, not backoff. A local file-browser path is not an uploaded Magic Hour file_path. Use the upload response or a permitted direct file URL, with the supported extension and an accessible input. When an error identifies the asset reference or file, correct that reference or complete the upload. Do not invent a missing generation response while repairing an asset.
Separate project errors from request errors
After creation, read the stored ID through Get video details: GET https://api.magichour.ai/v1/video-projects/{id}. A successful HTTP 200 can contain a failed project. Inspect status and the nullable error object instead of declaring success based on HTTP status alone.
The current states are draft, queued, rendering, complete, error and canceled. Preserve those exact wire values in your integration; “processing” can be a user-facing label for rendering, but it is not the current video status enum. Treat queued and rendering as unresolved work, not terminal errors. If your waiting budget ends, retain the project ID and resume or reconcile it later.
For status error, error.code and error.message describe the processing failure. These are project-level values, separate from the HTTP request-error enum above. The exact code and useful repair can vary by tool. Preserve both returned fields and keep a fallback for unfamiliar values instead of assuming one exhaustive cross-endpoint list.
A format or path error calls for a corrected asset. A prompt or input error calls for reviewing the submitted values. A policy-related error calls for reviewing the prompt and media against the content policy, changing affected content or contacting support if you believe it was a mistake. Repeated identical submissions are not a policy repair. An unknown or unrecognized error provides insufficient diagnosis for an automatic loop of new jobs; preserve the project and escalate or authorize a bounded new attempt deliberately.
Canceled is terminal for that project and does not emit a cancellation webhook. Stop polling that project as though it could complete, preserve the customer’s inputs and explain the cancellation. A new generation, if requested, is a separate action. Do not label a local HTTP timeout or exhausted waiting budget “canceled” unless the API actually reports that state.
Use bounded retry policies for safe reads
The development and recovery guidance distinguishes retrying a status read from creating another job. A client-side timeout does not cancel generation. For completion downloads, retry the existing output; if its signed URL is stale, read the same project again for current download information.
Choose a read retry policy that has both an attempt limit and an elapsed-time limit. For illustration, an application might retry a failed GET after approximately 1, 2 and 4 seconds, with random jitter, then hand the record to later reconciliation. Those numbers are a local policy example, not Magic Hour’s retry schedule, throughput limit or a video completion estimate.
Retry temporary connection failures and eligible server errors only within those bounds. Stop when the response identifies a condition requiring a correction. Avoid nested retries across HTTP client, queue and application layers: one layer should own the effective attempt budget, with other layers’ behavior accounted for. Preserve the last known project state separately from the last read error.
If your status GET returns HTTP 200 with queued, that is a successful read of pending work. It should follow your monitoring policy rather than incrementing a transport-failure counter. If the retry budget ends, show “We could not refresh the status; your request is still being checked” rather than declaring the media failed.
Idempotency belongs to the exact boundary
An internal intent ID can prevent double clicks from launching two simultaneous create calls through your own server. Enforce that ownership durably, so two workers cannot each submit the same intent. Preserve changed inputs as a deliberate new intent. A browser button being disabled is helpful presentation, but it is not enough to coordinate multiple requests or restarted workers.
That application control does not establish provider-side deduplication. The current recovery docs explicitly say not to assume repeated POST requests are deduplicated or that an Idempotency-Key header makes them safe. No supported creation idempotency-key contract was verified for the route above. Do not add an undocumented header and promise duplicate-charge protection.
There is still a difficult interval between sending a create request and saving its response. If acceptance is uncertain and no ID was captured, inspect your retained request/response records and project history in the Developer Hub. A descriptive name can help human reconciliation but is not a unique provider lookup or deduplication guarantee. If you cannot identify the project, keep the request unresolved and escalate with its time and parameters before authorizing another creation.
Illustrative handling walkthrough
A customer requests the approved product shot. Your server records intent product-shot-17 and receives a create response containing example-project. It saves that ID. The next status GET loses its connection. The following is a handling example, not an observed production incident.
The worker records a read transport error and retries GET for example-project within its local budget. It never returns to POST. If a later read reports rendering, the user sees pending work. If it reports complete with download information, the worker retrieves that existing output. If it reports error with a message identifying an unreadable image, the user is asked to re-export or replace the image before a separately authorized attempt.
In a different branch, the original POST connection fails before any ID is captured. The record becomes acceptance-uncertain, an application state distinct from the API project statuses. The user sees that the request is being checked, and a second click attaches to that record. History reconciliation comes before another create call. This branch cannot be resolved by pretending the missing response proves failure.
Recovery checklist and support record
Review every retry branch by method and operation. Confirm that status-read and download failures cannot re-enter creation, that terminal project states exit waiting, and that changed inputs produce a deliberate new attempt. Confirm that request fields, ID and last known state survive a page refresh or worker restart. Review automatic HTTP/SDK retries before enabling them on creation calls.
For support, retain internal intent ID, API endpoint, request time, account context, project ID when available, HTTP status/code, terminal project error and actions already attempted. Remove API secrets and signed URLs from shared logs. Include the relevant asset type and settings without exposing customer media unnecessarily. For unresolved acceptance, say explicitly that no ID was received; for a read failure, say that the ID exists but current status could not be read.
For an existing automation example, see image-to-video in n8n. For the broader application setup, keep the original integration handoff below; the endpoint references above own the precise request and recovery fields.
Original application integration source: Adding API to Your App.
Original endpoint and recovery source: https://docs.magichour.ai/integration/adding-api-to-your-app
Original endpoint and recovery source: https://docs.magichour.ai/api-reference/video-projects/get-video-details
Original endpoint and recovery source: https://docs.magichour.ai/integration/development-and-testing
Connect creation to the same-project recovery path
Use the current endpoint schemas above, save the returned ID, and keep unresolved acceptance separate from failed generation.
Open API app integrationFrequently asked questions
Retry eligible temporary failures of status reads or existing-output downloads with attempt and elapsed-time bounds. Fix request, authentication, account or policy problems first. A creation timeout or server error requires acceptance reconciliation before another POST.
Persist an internal request intent, coordinate submissions through durable application ownership, and save the provider project ID immediately. Retry reads for that same ID. Do not assume repeated POSTs or an undocumented Idempotency-Key header are deduplicated.
Show the last known project state separately from a read failure. Use explicit messages for pending work, terminal error, canceled and acceptance-uncertain requests, preserving inputs and offering the specific recovery action.

Continue Reading

How to evaluate AI media APIs: total time, cost and reliability

6 AI APIs for a weekend SaaS: architecture and launch checks (2027)

Image-to-video in n8n: reliable Magic Hour API workflow

Video face swap in n8n: reliable Magic Hour API workflow

