Edited script, same Idempotency-Key: 409 conflict on Sume TTS
Reusing an Idempotency-Key with a changed transcript returns 409 idempotency_conflict on Sume. How to key each script version so edits never collide.

If you change the transcript and reuse the same Idempotency-Key, Sume answers 409 idempotency_conflict and creates nothing. That is the safety working: the key means "this exact request". Give each script version its own key and the conflict never shows up, while a true retry of one version still returns the original job.
What the key promises
Send Idempotency-Key on any generation call. Repeat the identical request with the same key and you get the existing job back instead of a second charge. Repeat the key with a different payload and the API refuses. This holds for TTS 1.0, STT 1.0 and the music endpoints alike.
| Same key | Same payload | Result |
|---|---|---|
| Yes | Yes | The original job comes back; no new charge |
| Yes | No | 409 idempotency_conflict; nothing is created |
| No | Yes | A new job, a new charge |
| No | No | A new job, a new charge |
A key that tracks the edit
A good key names the intent, not the time. Hash the fields that define the audio, so an unchanged script reuses its key and a changed one gets a fresh one.
import hashlib
import json
def tts_key(project, transcript, avatar, language):
body = json.dumps(
[transcript, avatar, language], ensure_ascii=False
)
digest = hashlib.sha256(body.encode()).hexdigest()[:16]
return f"{project}-{digest}"
print(tts_key("promo", "Hello there.", "narrator", "en"))
print(tts_key("promo", "Hello there!", "narrator", "en"))Mistakes to avoid
- A fixed key like
testin a script: the second run with new text fails. - A timestamp key: every retry after a network error buys another job.
- Resubmitting after a sync timeout. A timed-out wait means the job is still running; poll
status_urlinstead.
Handling the 409
Treat idempotency_conflict as a bug in key construction, not as a transient error. Do not retry with the same key. Log the key and the changed field, then rebuild the key from the new payload and submit once. Sume does not document an expiry window in the pages I read, so do not rely on a key aging out.
Sources
Related posts
More in Developers
- Elysia on Bun: verify a Sume webhook with parse: "text"
An Elysia route that checks the Sume HMAC signature on the raw string, refuses an empty secret, skips duplicates and answers webhook.test. Tested on Bun 1.4.
- Estimate a 12 s 9:16 1080p Seedance 2.5 clip before running it: $17.06
A 12-second 9:16 1080p Seedance 2.5 clip is 583,200 video tokens, $17.06 on Sume; here is the arithmetic so you can quote any clip before running it.
- Price a mixed image batch first: endpoint pricing in Python
Read cost_usd from each Sume image endpoint and multiply by the count. 200 Grok, 50 Seedream 4.5 and 100 Flux 2 Pro images should total $11.25 before you spend.
- Estimate a Gemini TTS bill from seconds of audio (Python, 25 tok/s)
A 20-line Python estimator for Gemini 3.8 Flash and Flash-Lite TTS audio output cost from seconds, at 25 tokens per second and Google's 2026 and 2027 rates.
Written by Sume