Idempotency & Retries
Make a generation request safe to send twice.
Send Idempotency-Key on every generation request:
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000Repeating a key with the same body returns the task that key already created —
nothing is reserved, charged or generated a second time — and the response
carries Idempotency-Replayed: true.
Without a key nothing changes: the endpoint behaves as it always has, and a retry creates a second generation. The header is optional. We strongly recommend it.
When to retry
Generation submissions are safe to retry when you send an
Idempotency-Key — see idempotency below. Without one, a
retried POST is a second generation and a second charge.
| Situation | What to do |
|---|---|
| Network timeout, connection dropped | Retry with the same key and the same body. |
500, 503 | Retry with the same key, backing off. |
429 | Wait Retry-After seconds, then retry with the same key. It was not consumed. |
402 | Add funds, then retry with the same key. It was not consumed. |
400, 401, 413 | Fix the request or the credentials. The key was not consumed. |
409 IDEMPOTENCY_KEY_REUSED | Do not retry that key with a different body. Use a new key. |
Task is QUEUED or PROCESSING | Poll it. Do not resubmit the generation. |
Task is FAILED | A new attempt needs a new key — see below. |
A 429 carries a Retry-After header with the seconds until the window
resets. Honour it rather than retrying immediately.
The rules
Send Idempotency-Key on every generation request:
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000The value is yours to choose: any 1–128 printable ASCII characters. A UUID per logical generation is the easy answer, but a stable id you already have — an order id, a row id, a job id — works just as well. What matters is that one logical generation keeps one key across every retry of it, and that a genuinely new generation gets a new one.
One key, one generation. Repeating a key with the same body returns the task
that key already created, and the response carries Idempotency-Replayed: true.
Nothing is reserved, charged or sent for generation a second time.
A retry is not a new attempt. If the task a key created ended up FAILED or
CANCELLED, replaying that key returns the same finished task. That is
deliberate — it is what stops a retrying client paying twice. To genuinely try
again, send a new key.
Same key, different request, 409. If a key comes back with a materially
different body — a changed prompt, resolution, duration or assetId — the
request is refused rather than answered with a task you did not ask for. Field
order and omitted fields that equal their defaults are not differences:
{"prompt": "x"} and {"prompt": "x", "resolution": "1k"} are the same
request.
Keys are per account, per endpoint. Another account using the same value does not collide with yours, and the same value sent to text-to-image and to text-to-video creates two independent generations. Rotating your API key does not disturb keys already in use.
Without a key, nothing changes: the endpoint behaves as it always has, and a retry creates a second generation. The header is optional. We strongly recommend it.