Episode idempotency keys: season, episode and version for Sume runs

Build the Sume Idempotency-Key from series, season, episode and a version you bump on purpose. What replays, what conflicts, what needs a new key.

5 min readSume
All posts

For an episodic series, derive the Idempotency-Key from what the episode is, not from when you asked: series slug, season, episode number, and a version you bump only when you deliberately want a fresh render, such as brand-series:s01e03:v1. Sume's docs say a uuidgen per request makes the header decorative, because a double click or a redelivered job then turns into two paid runs.

The key is up to 255 characters and is scoped to one Format, so the same string sent to two Formats starts two runs. That matters for a series with a separate Format for the cold open and for the main episode: the same episode key is safe on both.

What each replay does

These rules come from the Format call page and apply to every episode you submit.

Replay behaviour for a Format run (as of 2026-10-03)
What you sendResult
Same key, same body200 with the original receipt and idempotency_hit: true; no second run, no second charge
Same key, different body (even a different instruction or attachment list)409 idempotency_conflict; nothing runs
Same key, two requests at onceOne wins; the other gets retryable 409 idempotency_key_in_use; wait about a second and resend
Same key after a create that failed (402, 503)The key was released; fix the cause and retry with the same key
No keyEvery call starts a new paid run

A key function

Keep the pieces readable. The embed cookbook hashes its pieces; for a series you usually want to read the key in a log and in the dashboard, so plain text is fine as long as it stays under 255 characters.

def episode_key(series: str, season: int, episode: int, version: int = 1) -> str:
    if not series or season < 1 or episode < 1 or version < 1:
        raise ValueError("series, season, episode and version are required")
    key = f"{series}:s{season:02d}e{episode:02d}:v{version}"
    if len(key) > 255:
        raise ValueError("Idempotency-Key must be 255 characters or fewer")
    return key

assert episode_key("brand-series", 1, 3) == "brand-series:s01e03:v1"
assert episode_key("brand-series", 1, 3, 2) == "brand-series:s01e03:v2"

When to bump the version

  • Bump it when you change the episode body on purpose, for example a new script. The old key would return 409 idempotency_conflict because the body differs.
  • Bump it to retry a failed run. The old key is bound to the run that already failed, so reusing it returns that same failed receipt.
  • Do not bump it for a network retry of the same request. The replay returns the original receipt and you pay once.
  • For a reshoot of one scene, continue the run with previous_run_id and a new key such as brand-series:s01e03:v1-retry-sc7.

Bulk queues are different

A bulk create takes the key from the Idempotency-Key header or an idempotency_key body field, and the header wins. Replaying the same key with the same { concurrency, items } returns 202 and the existing queue; a different payload returns 409 idempotency_conflict with details.queue_id. Mint a fresh queue key per season batch, because replaying a spent key returns the old queue, not a new one. Per-item keys are not part of the queue envelope, so keep your per-episode keys in your own ledger.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume