Workflow DevKit replays: a stable Idempotency-Key for Sume submits

Workflow DevKit 4.8.12 fixed replay clock tracking. A replayed step must send the same Sume Idempotency-Key, so derive it from the run id, not Date.now.

4 min readSume
All posts

Workflow DevKit v4.8.12, dated October 2, 2026, fixed deterministic clock tracking where concurrent replays called Date.now with different amounts of events read from the log. The same lesson applies to Sume submits: a step that is replayed must send the same Idempotency-Key each time. Build the key from the workflow run id and step name, never from Date.now.

What the release says

From the Vercel release updates page, read on 2026-10-03: the release fixed deterministic clock tracking, and correlation IDs are preserved across concurrent step replays. See the release for the details of the fix.

Why replay and billing meet

A durable workflow re-runs code from its log. If a step submits a paid job and the process dies before the result is recorded, the step runs again. With a key derived from the clock or a random value, the second run looks like a new request and can create a second paid job.

What Sume guarantees with a key

Sume's docs say to send Idempotency-Key on submit requests when retrying after a client-side timeout or network failure, to reuse the same key only for the same operation and payload, and that a retried submit with the same key returns the original job. A client timeout does not cancel the job, which keeps running and billing.

Key sources (read 2026-10-03)
Key derived fromReplay-safe?Why
Workflow run id plus step nameYesIdentical on every replay
Date.now()NoDiffers between replays
Random UUID in step bodyNoNew on every execution
Random UUID stored by a previous stepYesReplays return the logged value

A stable key in code

Pass the run id in from the workflow context and add a step label, plus a version if the payload changes.

async function submitScene(runId: string, scene: number, prompt: string) {
  const res = await fetch("https://api.sume.com/v1/videos", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SUME_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": `${runId}:scene-${scene}:v1`,
    },
    body: JSON.stringify({ model: "sume/auto", prompt }),
  });
  if (!res.ok) throw new Error(`submit failed: ${res.status}`);
  return (await res.json()).id as string;
}

Change the key when the payload changes

If you edit the prompt, bump the version in the key. Reusing a key for a different payload is outside what the docs promise. Store the returned job id in the workflow state and poll it, rather than submitting again.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume