Retry-on-timeout wrapper from the Sora days? Add an idempotency key
A wrapper that retries a video submit on timeout can create two paid Sume jobs. Build an Idempotency-Key from the request, and learn what a replay returns.

Older video code often retries a create call when the network times out. On Sume that can bill twice, because the first request may have succeeded. The errors guide says not to retry unsafe submit requests without an Idempotency-Key, and the jobs guide says to send one when retrying after client-side timeouts or network failures. Derive the key from the request itself and reuse it for exact retries only.
What the key promises
The docs say a replay returns the original job, and that reusing a key for a different operation or payload returns 409 idempotency_conflict. The two rules give you a design: same intent, same key; different intent, different key.
| Situation | Result |
|---|---|
| Same key, same body, after a timeout | Original job returned |
| Same key, different body | 409 idempotency_conflict |
| New key, same body | A new paid job |
| Retry after 429 queue_full with same key | Allowed; the reservation was released |
| Retry after 503 provider_capacity_exceeded | Same key, later |
Build the key from the intent
Hash the fields that define the job: model, prompt, duration, resolution, aspect ratio, input URLs, plus a business identifier such as the order or scene id. A random UUID per attempt defeats the purpose, because the retry gets a new key. A timestamp does too. If two users legitimately want the same prompt rendered separately, include the user or order id so the keys differ.
import hashlib, json
def idem_key(order_id: str, body: dict) -> str:
raw = json.dumps(body, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(raw.encode()).hexdigest()[:24]
return f"{order_id}-{digest}"
print(idem_key("order-1042", {"model": "seedance-2", "prompt": "a red kite"}))Deliberate re-renders
When a user clicks regenerate, you want a new take, so include a take number in the key and show the cost again. The docs also say not to resubmit a paid request just because a local worker timed out; poll the stored job id instead. Both rules fit one policy: retry the same key for network trouble, new key for a new decision.
Check it works
In staging, send the same request twice with one key and confirm both calls return the same job id and that your balance reservation appears once in GET /v1/usage. Then change the prompt and keep the key, and confirm you get the conflict. The video generation docs list the submit fields the key should cover.
Sources
Related posts
More in Developers
- Retry policy by Sume job error category
Sume failed jobs carry a category and retryability. Retry queue and capacity errors with a cap, stop on validation and quota, and skip blanket retries.
- Expiring API keys: Sume key metadata and rotation habits
OpenAI added enforced key lifetimes in Sep 2026. Sume's docs list key id, name, prefix, scopes and last-used time, so rotate on a schedule you keep.
- Run an OpenRouter-style image script against Sume: four changes
Moving a script from OpenRouter's /api/v1/images to Sume's /v1/images: base64 becomes a hosted URL, 202 jobs appear, stream and seed return 400. Python check.
- Run your own 10-clip word error test on Sume STT for 10 cents
Microsoft ranks MAI-Transcribe-2-Streaming first on Artificial Analysis. To know your own audio, score 10 one-minute clips with a 15-line WER function.
Written by Sume