One idempotency key per prompt row: re-run a 1,000-clip library safely
Derive the Idempotency-Key from every field you send, so a crashed batch can restart without paying twice and a changed row never collides. Python, 17 lines.

Build the Idempotency-Key as a hash of every field you send in the request body, and you can restart a 1,000-prompt library at any point without paying twice. An exact retry returns the original job. A row whose model, resolution or length changed hashes to a new key, so it never hits the 409 idempotency_conflict that Sume returns when a key is reused for a different payload.
After OpenAI removed the Videos API on 2026-09-24, many libraries are being re-rendered in bulk with scripts that will be killed and restarted. A key tied to the row content makes that safe.
The rule from the docs
The Sume docs say to send Idempotency-Key on submit requests that a client can retry, and to use the same key again only for the same operation and payload. A replay returns the original job and does not bill a second job. A key reused with a different payload fails with 409 idempotency_conflict.
A key function
This function canonicalizes the fields that define a clip, sorts them, and hashes them. It includes callback_url, because a different callback is a different request. The two assertions at the bottom print True and False: the same row gives the same key, and a changed resolution gives a new one.
import hashlib
import json
FIELDS = ("model", "prompt", "resolution", "aspect_ratio", "duration", "callback_url")
def idem_key(row):
body = {k: row.get(k) for k in FIELDS if row.get(k) is not None}
canon = json.dumps(body, sort_keys=True, separators=(",", ":"))
return "lib-" + hashlib.sha256(canon.encode()).hexdigest()[:40]
a = {"model": "wan-3.0", "prompt": "Mug on a desk", "resolution": "720p",
"aspect_ratio": "9:16", "duration": 8}
b = dict(a, resolution="1080p")
print(idem_key(a) == idem_key(dict(a)))
print(idem_key(a) == idem_key(b))
What a replay looks like
Run the script twice on the same table. The second run recomputes the same keys, Sume returns the original jobs, and you pay once. Store the returned id against the row on the first run, and on the second run skip rows that already hold a completed result, so you do not even send the replay.
If the table gets edited between runs, only the edited rows hash to new keys. That is the behavior you want: an unchanged prompt is a replay, and an edited one is a new clip that you do pay for.
Choices that keep it safe
Hash the fields you send, not the row id. If you use the row id alone and later edit the prompt in that row, the replay will either hand you the old job or conflict. The hash has 40 hex characters; the docs do not give a maximum key length here, so stay short and printable.
Do not put a timestamp or a random value in the key. The point is that a restarted script computes the same key as the crashed one. When you want a deliberate second render of the same row, add a take number to the hashed fields and increase it.
- Set the key on the first attempt, not only on retries.
- Log the key with the job id so you can find a job from a row.
- Retry only
429,503and network errors with the same key, and honorretry-after. - A
402 insufficient_creditsis not a retry case: fix the balance first.
Sources
Related posts
More in Developers
- Image 1.0 defaults to low quality; GPT Image 2.5 defaults to high
Same prompt, two Sume routes, two defaults: Image 1.0 omits quality as low, POST /v1/images with GPT Image 2.5 omits it as high. Set quality in both.
- Image 1.0 to POST /v1/images: image_urls becomes input_references
Move a Sume Image 1.0 request to POST /v1/images: image_urls to input_references, mask_image_url to mask_url, num_images to n, plus new defaults.
- Image API returned 202 after 30 seconds: a Python poll that finishes
POST /v1/images waits 30 seconds, then returns 202 with a job envelope for slow high-quality runs. A 25-line Python script that handles both 200 and 202.
- Sume image_size vs aspect_ratio: 1080x1350 and GPT size limits
image_size wins over aspect_ratio on Sume's image API. On Nano Banana 1080x1350 becomes 4:5 plus target pixels; GPT needs multiples of 16. Rules and checks.
Written by Sume