Same Idempotency-Key replay: bulk run answers 202, single run 200
Replaying a Format bulk-run create returns 202 and the original queue with no idempotency_hit flag. A single run returns 200 with idempotency_hit true.

If you replay a Sume Format bulk-run create with the same Idempotency-Key and the same body, you get 202 and the queue that already exists. You do not get 200, and the queue has no idempotency_hit field. A single Format run behaves differently: the replay returns 200 with idempotency_hit: true. Stripe's idempotency page describes the idea both follow, saving the result of the first request for a key and returning it for later requests, but the status code is where a Sume client can trip.
Two surfaces, two replay signals
On POST /v1/formats/{handle}/{slug}/runs, 202 means a fresh run and 200 means an idempotent replay. Both carry the full receipt. On POST /v1/formats/{handle}/{slug}/bulk-runs, a replay stays 202. The queue object carries id, counts and items, and nothing marks it as a replay, so a client that branches on 202 versus 200 to detect a duplicate will mis-handle bulk creates.
The scope of the key is one Format. The header form wins if you also send idempotency_key in the body. A different payload under the same key gives 409 idempotency_conflict, and details.queue_id names the original queue.
| Call | Fresh | Same key, same body | Same key, other body |
|---|---|---|---|
| Single Format run | 202 | 200 with idempotency_hit: true | 409 idempotency_conflict |
| Bulk run create | 202 | 202, the existing queue | 409, details.queue_id names the first queue |
| Stripe (reference) | Result saved | Same result, including 500s | Error on mismatched parameters |
How to detect a bulk replay
Do not infer replay from the status code. Persist the data.id (frq_...) you received for each batch key. When a create returns, compare: the same id means you are looking at the queue you already know. A new id under a key you thought was new means the key was not spent the way you expected, so stop and investigate before any further submit.
curl -sS -X POST "https://api.sume.com/v1/formats/chase/product-promo/bulk-runs" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: promo-2026-10-05-batch-1" \
-d '{"concurrency": 2, "items": [{"instruction": "clip 1"}, {"instruction": "clip 2"}]}' \
| jq -r '.data.id, .data.status, .data.counts.total'Mint a fresh key for each batch
The expensive mistake is the opposite one. If you reuse a spent key for a new list that happens to be identical, you will quietly get the old queue back and run nothing new. Build the key from the thing that makes the batch unique, such as a date and a batch number, and keep it with the queue id in your own table. Stripe notes that keys may be pruned after 24 hours, so do not treat an old key as a permanent lock; Sume's docs describe no such window, so store both ids and rely on the queue id for lookups.
Sources
Related posts
More in Formats
- Same intro and outro on every Short: allowed on YouTube?
YouTube allows a repeated intro and outro if the rest differs. What that means for AI-made Shorts built on a fixed format, and how to vary the body.
- Cancel one bulk-run child: pay for what finished, slot moves on
Cancel a Format run inside a bulk queue with POST /v1/format-runs/{run_id}/cancel. The item turns canceled, its slot starts the next one, no webhook fires.
- Change a Format grant role: PATCH run to write and back
PATCH .../grants/{workspace} with {role} changes a pending or accepted grant. Raising to write applies on the next authoring call; lowering to run closes it now
- Change only the CTA of a finished ad: previous_run_id on a Format
Re-do one line of a finished Sume Format ad without paying for the whole ad again: previous_run_id, a new key and cap, and the four refusals to expect.
Written by Sume