Choosing a Sume Idempotency-Key: business key plus a payload version
A good Idempotency-Key is stable across retries and changes with the request. Build it from your order id and a payload hash, or hit 409 idempotency_conflict.

Derive the Sume Idempotency-Key from something stable about the work, like an order id, plus a short hash of the exact payload. A retry then reuses the key and gets the original job back, while a deliberately edited request gets a fresh key instead of 409 idempotency_conflict.
The rules from the docs
Send the header on submits you may retry after a timeout or network failure, and reuse a key only for the same operation and payload. Reusing a key with a different body is 409 idempotency_conflict; do not retry that as-is, fix how you derive the key. idempotency_key_in_use is a different 409, where another request with the same key is still in flight and you can resend after about a second.
A derivation that works
Canonicalize the body so key order cannot change the hash. Do not put timestamps or random values in the hashed input, or every retry looks new and you pay twice.
import asyncio
import hashlib
import json
def idempotency_key(order_id: str, payload: dict) -> str:
canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(canonical.encode()).hexdigest()[:12]
return f"order-{order_id}-{digest}"
async def main() -> None:
a = idempotency_key("8823", {"prompt": "mug", "duration": 6})
b = idempotency_key("8823", {"duration": 6, "prompt": "mug"})
c = idempotency_key("8823", {"prompt": "mug", "duration": 8})
print(a == b, a == c) # True False
asyncio.run(main())When you want a new job on purpose
Changing the payload changes the key, so you get a new paid job; that is intended for an edit. For a failed Format run, the docs say to retry with a new key, so mint one deliberately rather than reusing the failed one.
| Situation | Result |
|---|---|
| Retry with same key and body | Original job returned |
| Same key, different body | 409 idempotency_conflict |
| Same key, first request in flight | 409 idempotency_key_in_use, resend soon |
Sources
Related posts
More in Developers
- Retry Sume 429s in TypeScript: a fetch wrapper that obeys retry-after
A small fetch wrapper for the Sume API: retry 429 only when the request is a GET or carries an Idempotency-Key, wait retry-after, and never loop on queue_full.
- Sume reserve, capture, refund: what your cost ledger should mirror
Sume reserves the estimate at submit, captures it on success and releases it on failure or cancel. Mirror the three states or cost reports will double count.
- Sume SDK returns {data, error}, not exceptions: an unwrap helper
Generated @sume-com/sdk operations resolve with data, error and response instead of throwing. Wrap them in an unwrap helper that throws a typed error.
- Where the Sume TypeScript SDK runs: Node 18+, Bun, Deno and Workers
@sume-com/sdk has no runtime dependencies and needs only fetch and WebCrypto. Install it, create a client, and know which options and helpers it adds.
Written by Sume