Same idempotency key, new body: Sume Format run 409 vs 200 replay
Same Idempotency-Key and body on a Sume Format run gives 200 with idempotency_hit true. A changed body or attachments gives 409. Bulk replays stay 202.

Send the same Idempotency-Key with the same body to POST /v1/formats/{handle}/{slug}/runs and Sume returns 200 with the original receipt and idempotency_hit: true, with no second run and no second charge. Send the same key with a different body and you get 409 idempotency_conflict, and nothing runs.
The behavior is in the Calling a Format docs. A different instruction or a different attachment list counts as a different body, which is the part people forget.
Replay outcomes
The scope of a key is one Format, and a key can be up to 255 characters. The same key sent to two Formats starts two runs.
| Situation | Result |
|---|---|
| Same key, same body | 200, original receipt, idempotency_hit: true |
| Same key, different body or attachments | 409 idempotency_conflict, nothing runs |
| Same key, two requests at the same moment | One wins; the other gets 409 idempotency_key_in_use, retryable after about one second |
| Same key after a failed create (402, 503, ...) | Key was released; fix the cause and retry with the same key |
| Bulk queue, same key, same payload | 202 with the old queue (no idempotency_hit field) |
| Bulk queue, same key, different payload | 409 idempotency_conflict, details.queue_id names the original |
Deriving the key
Derive the key from the item the run makes: your order id plus a version number that you bump only when you want a re-run. Do not use the time of the request, and do not call a new uuidgen per attempt, because then the header does nothing and a retry after a timeout starts a second paid run.
Example: order 8841 with version 1 gives the key order-8841-v1. A network timeout, then a retry with the same key and body, returns the same run. A deliberate re-run with new copy uses order-8841-v2.
import uuid
def run_key(order_id: int, version: int) -> str:
return f"order-{order_id}-v{version}"
print(run_key(8841, 1)) # retry-safe
print(run_key(8841, 2)) # deliberate re-run
print(str(uuid.uuid4())[:8], "<- a fresh uuid per attempt defeats the header")Handling the 409s
A conflict means your code reused a key for new work, so look for a version that did not change. idempotency_key_in_use is the other 409 and it is retryable: wait about one second, then send again to get the original run.
- Bulk queues take the key as the header or a body
idempotency_key; the header wins if both are sent. - Mint a fresh key per batch, because a spent key returns the old queue.
- Store
data.idfrom the first response and use the receipt URLs it carries.
Why the same-moment case matters
Two workers that retry on a timeout at the same instant can both send the key. Only one wins. The other gets idempotency_key_in_use, and the docs call it retryable: wait roughly a second, send again, and you receive the original run. Build the retry as part of the client and you never need a lock of your own. If a create fails with a 402 or 503, the key is released, so the same key is safe to reuse once the cause is fixed, for example after topping up credits.
Sources
More in Formats
- Sume Format output_error codes: which to retry and which to fix
output_extraction_failed is transient: re-read the run, then retry with a new key. output_schema_unsatisfied means the schema or recipe is wrong. Six codes.
- Team Format returns 403 workspace_key_required: which key to mint
A personal key on a team Format gets 403 workspace_key_required. details.workspace_id names the workspace. Create the key there. Other keys see 404.
- Customer text in a video prompt: input vs instruction in Sume
Put customer-supplied text in the Sume Format input object, stored as data, and keep your own directive in the instruction. Here is why that split helps.
- Format works in chat but fails over the API? The approval gate
A Sume Format that pauses for approval in chat runs unattended over the API. See what changes, why unattended_blocked appears, and a pre-flight list.
Written by Sume