# Errors and recovery

Retain operation identity across failures.

## Response envelopes

Success: {"data":{...},"meta":{"request_id":"req_...","api_version":"2026-10-01"}}. Errors: {"error":{"code":"validation_error","message":"Check the request fields.","request_id":"req_...","details":[{"field":"budget_cents","message":"..."}]}}. X-Request-Id is included in responses. Persistent/API responses are private and no-store.

JSON bodies have a 16384-byte limit and reject unsupported fields. Send Content-Type: application/json. Advertising, conversion, and funding amounts are integer USD cents. Creative usage.provider_cost_usd is a nullable number in USD major units; it is not a quote or settled invoice.

## Decide what to do next

| Status / code | Action |
| --- | --- |
| 400 invalid_json or idempotency_key_required | Correct the request, then retry. |
| 401 unauthorized | Ask the owner for a valid, unrevoked agent key. |
| 403 owner_approval_required, owner_required, insufficient_scope | Request the appropriate owner action or scope. Never borrow owner credentials. |
| 404 not_found | Check the resource ID and workspace. |
| 409 idempotency_conflict | Read the existing request; use a new key only for an intentionally new operation. |
| 409 advertiser_setup_required / advertiser_consent_required | Owner/operator setup is incomplete. |
| 409 live_launch_disabled / billing_disabled | The deployment gate is closed; do not retry to bypass it. |
| 409 insufficient_funding / insufficient_allocation | Owner payment or operator allowance is required. |
| 409 pixel_not_ready / conversion_not_verified | Install and validate tracking before seeking launch. |
| 409 provider_operation_in_progress | Poll status and retry with backoff. |
| 409 provider_idempotency_expired | Stop automatic retries and ask the operator to reconcile the original operation. |
| 413 payload_too_large | Reduce JSON size; use direct file upload for images. |
| 422 validation_error / invalid_creative | Correct the indicated field. |
| 429 provider_rate_limited | Respect Retry-After if present; otherwise back off. |
| 429 creative_generation_limit / 503 creative_generation_capacity | Lifetime beta capacity is exhausted. Stop generation; automatic retries cannot replenish it. |
| 503 creative_generation_unavailable | Generation is not enabled/configured. Read capabilities and stop new jobs. |
| 409 creative_generation_in_progress / creative_publish_in_progress | Read the existing job and wait; keep its ID. |
| 409 creative_image_not_ready | Inspect job progress and selected index; a saved image is required. |
| 409 advertiser_not_ready / 403 advertiser_binding_mismatch | Resolve advertiser assignment, consent or destination before publication. |
| 502 provider_outcome_unknown | A write may have happened. Keep the operation identity and reconcile. |
| 503 database_unavailable / provider_setup_required | Retry reads later; preserve write keys and request IDs. |

## Bounded retries

Use exponential backoff with jitter, for example 2, 4, 8, 16, then 30 seconds. Bound the total attempts and escalate with request_id and campaign ID. Never loop approval or create requests with fresh keys after timeouts. An HTTP failure cannot prove that an upstream write did not occur.

## Creative jobs can fail after acceptance

A 202 response reserves a job; it is not a completed image. Read status, stage, error, and variants. Provider errors after acceptance appear in data.error with status attention_required while the read itself returns HTTP 200. Saved partial variants remain available.

creative_provider_setup_required, creative_provider_access_required, and creative_provider_limit require operator/provider configuration or billing review. creative_provider_rejected requires correcting the brief or reviewing provider restrictions. generation_time_limit means the processing budget ended; inspect any saved variants. creative_outcome_unknown or generation_outcome_unknown means a paid call may have completed. Stop the loop and ask for reconciliation; never silently create a replacement job or use a fresh idempotency key.

Read failures such as creative_preview_unavailable may be retried without regenerating. An expired signed image URL only needs another job read. Publishing uses the already stored image: retry the same publish job/index to resolve processing, and inspect publish_status. A publish failure is returned as an HTTP error and may mark that variant attention_required without changing the generation job's error field. Never use a file ID in a campaign until publish_status is ready.
