Cloudflare Workflow schedules: one Sume Idempotency-Key per tick

A scheduled Cloudflare Workflow that submits a Sume job should derive the Idempotency-Key from the tick, so a replayed step returns the same job.

4 min readSume
All posts

Build the Sume Idempotency-Key from the schedule tick, for example the hour the cron fired, and reuse that exact key every time the step runs. A retried or replayed submit then returns the original job instead of creating and billing a second one. The Sume docs say a retried submit must reuse the same key.

The schedule syntax is from Cloudflare's Workflows changelog; the key rules are from Sume's Jobs and results, both read 2026-09-30.

What does the Cloudflare change add?

The changelog says you can declare a Workflow in the exports field of your Wrangler config, keyed by the class that extends WorkflowEntrypoint, with type set to workflow, a name, optional limits such as steps, and a schedules array of cron strings. Its example is "0 * * * *", a cron string that fires at the top of each hour.

{
  "exports": {
    "MyWorkflow": {
      "type": "workflow",
      "name": "my-workflow",
      "schedules": ["0 * * * *"]
    }
  }
}

Why does the key come from the tick?

A Workflow step can run again after a failure. If each run made up a new random key, the replay would be a new paid request. A key built from the tick is the same on every attempt for that tick and different for the next one.

Sume submit and retry rules from the docs, read 2026-09-30: https://docs.sume.com/workflows/jobs-and-results
SituationWhat the docs say
Retried submitReuse the same Idempotency-Key; the retry returns the original job
Local timeoutDo not resubmit the original paid request
Default modeOmit mode and you get async
Key shape in the docshero-shot-2026-08-03-001
Failed webhook sendA failed delivery is not a failed job

What does the step look like?

Compute the key outside the retried work, using the scheduled time rather than the current time. The changelog page does not say what a scheduled run receives, so take the tick from whatever scheduled time your Workflow exposes; the code below takes a timestamp and floors it to the hour.

export function tickKey(scheduledMs: number): string {
  const hour = new Date(Math.floor(scheduledMs / 3600000) * 3600000)
    .toISOString()
    .slice(0, 13);
  return "hero-shot-" + hour;
}

export async function submit(apiKey: string, scheduledMs: number) {
  const res = await fetch("https://api.sume.com/v1/image-1.0/generate", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + apiKey,
      "Content-Type": "application/json",
      "Idempotency-Key": tickKey(scheduledMs),
    },
    body: JSON.stringify({ prompt: "Product hero shot on marble", mode: "async" }),
  });
  return res.json();
}

How should the Workflow wait for the result?

The submit returns a job id first, and a 2xx means the job exists, not that it finished. Poll GET status_url with backoff, or receive a webhook and keep polling as a backup. A failed webhook delivery leaves a job that still reached its real state. Workers cron for AI video covers the older cron-trigger route.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume