Idempotency keys for AI video APIs: retry without paying twice
An idempotency key makes a retried create return the original run or job instead of a second paid one. How Sume's Idempotency-Key works on each API.

An idempotency key is a string you send with a paid create request so that a retry returns the original run or job instead of starting, and billing, a second one. On Sume, send an Idempotency-Key header on every create and derive it from the thing being made, such as an order id plus a version, not from the moment of asking.
The rules below come from Sume's Create a run, Jobs and results, Video Generation, Agent Completions, and MCP tools and gates docs pages, read on 2026-09-25.
Why do AI video APIs need idempotency keys?
Video work outlasts the request that asked for it. Even a sync submit waits at most 30 seconds, and video jobs routinely take longer. A 2xx means the job exists and paid work is in flight, not that it finished, and a client-side timeout does not cancel the job: it keeps running and still bills.
So do not resubmit a paid request just because a local process timed out. If you must retry the submit, reuse the same Idempotency-Key, and the retry returns the original job instead of billing a second one.
How should I build an idempotency key?
- Derive it from stable identifiers: your order id and a version you bump when you deliberately want a re-run.
- Never generate one per request. A
uuidgenper request makes the header decorative. - Reuse a key only for the same operation and payload.
- On Format runs, a key is up to 255 characters, and the body field
idempotency_keyalso works; the header wins when both are sent.
curl -sS -X POST "https://api.sume.com/v1/formats/acme/product-promo/runs" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-8823-promo-v1" \
-d '{ "input": { "product_url": "https://shop.example.com/p/8823" } }'What happens when I replay a key?
On a Format run, a fresh create answers 202 and a replay answers 200 with the original receipt, so your code can treat both as success and store data.id. The full set of outcomes, from Idempotency:
| Replay | Result |
|---|---|
| Same key, same body | 200 with the original receipt and idempotency_hit: true. No second run, no second charge. |
Same key, different body, including a different instruction or attachment list | 409 idempotency_conflict. Nothing runs. |
| Same key, two requests at the same moment | One wins; the other gets 409 idempotency_key_in_use, which is retryable. Wait about a second and resend. |
Same key after a create that failed (402, 503, …) | The key was released. Fix the cause and retry with the same key. |
Which Sume endpoints accept idempotency keys?
Every create surface below takes one. On POST /v1/videos, the key is one of the documented differences from the OpenRouter Video Generation API, which has none on that route; with model: "sume/auto", a replay also prices and routes identically. More in OpenRouter-compatible video generation.
| Surface | How to send it | On replay |
|---|---|---|
| Format runs | Idempotency-Key header on every create | 200, the original receipt, idempotency_hit: true |
| Agent Completions | Idempotency-Key header | The original receipt with idempotency_hit: true |
| Generation job submits | Idempotency-Key header | The original job instead of a second bill |
POST /v1/videos | Idempotency-Key header | The original job |
| Hosted MCP write and paid tools | idempotency_key argument, required | Used for transport and dedup; it is not human approval |
curl -sS -X POST "https://api.sume.com/v1/videos" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: desk-clip-8823-v1" \
-d '{
"model": "sume/auto",
"prompt": "A vertical UGC-style product clip on a desk, natural light",
"aspect_ratio": "9:16",
"duration": 5
}'What should I do after a timeout instead of resubmitting?
Pick the existing job back up. The steps below are from Jobs and results.
- Poll the job you already have at
GET /v1/jobs/{id}/statuswith exponential backoff, honoringnext_poll_after_secondswhen present. A job created on/v1/videosis visible there too. - A
syncsubmit that runs out of wait budget still returns2xxwith the job id. Continue withstatus_url. - On the hosted MCP server,
jobs_waitholds at most 55s per call. Onwait_slice_expired, or a524transport failure, calljobs_waitagain on the same ids; never resubmit the paid create. - A client-side timeout cancels nothing.
POST /v1/jobs/{id}/canceldoes, but only before generation work starts.
What does an idempotency key not do?
- It does not approve spend. For a preview, hosted MCP tools take
dry_run=true; for a cap,max_spend_usd, which is enforced only when you send it. See spend caps for unattended AI agents. - It does not cover a changed request. The same key with a different body is a
409, not a new run. - It does not span Formats. The same key sent to two Formats starts two runs.
Sources
Related posts
Written by Sume