Deno: time out a Sume video submit, then retry with the same key

A fetch that times out may still have created a job. A 20-line Deno submit retries only 408, 429, 5xx and timeouts, always with one Idempotency-Key.

4 min readSume
All posts

Generate one Idempotency-Key per intended render, send it on every attempt, and retry only when the outcome is unknown: a timeout, a network error, 408, 429 or a 5xx. A timed-out fetch tells you nothing about the server. Sume's video docs say a replay with the same key returns the original job, so the retry cannot bill a second clip.

What counts as unresolved

The typed error docs for the paid create endpoints say a failed response proves the work was refused only for a validation, authorization or balance reason, and that a 5xx never proves it. That rule gives the retry set below.

Retry decision for a paid submit (Sume docs, read 2026-10-07)
OutcomeRetry with the same key?Why
Timeout or network errorYesThe job may already exist
408, 429, 5xxYesTransient; honor retry-after on 429
400, 402NoFix the request or the balance first
409 idempotency_conflictNoSame key, different payload; error details name the existing job
202DoneStore the id

The submit

Run it with deno run --allow-net --allow-env. The key is made once at module load, which is what keeps retries identical; in a real service, store it with the row before the first attempt so a restart reuses it. Top-level await is fine in Deno, unlike in a Python script.

const base = Deno.env.get("SUME_BASE") ?? "https://api.sume.com";
// Make the key once per intended render and store it with the row, so a restart reuses it.
const key = "veo-migrate-" + crypto.randomUUID();
const retryable = (s: number) => s === 408 || s === 429 || s >= 500;

async function submit(): Promise<{ id: string }> {
  for (let attempt = 1; ; attempt++) {
    const res = await fetch(`${base}/v1/videos`, {
      method: "POST",
      headers: { Authorization: `Bearer ${Deno.env.get("SUME_API_KEY")}`, "Content-Type": "application/json", "Idempotency-Key": key },
      body: JSON.stringify({ model: "gemini-omni-flash-1.1", prompt: "a lighthouse in fog" }),
      signal: AbortSignal.timeout(30_000),
    }).catch(() => null); // timeout or network error: the job may already exist
    if (res?.status === 202) return await res.json();
    if (res && !retryable(res.status)) throw new Error(`HTTP ${res.status}: fix the request, do not retry`);
    if (attempt === 3) throw new Error(`gave up; a job may exist under key ${key}`);
    console.log(`attempt ${attempt} unresolved, retrying with the same key`);
  }
}
console.log(await submit());

Where it stops

After three tries the function throws and says a job may exist under the key. Do not mint a new key at that point. Retry later with the same one, or list jobs and match on idempotency_key, which every job object carries. This sample also does no backoff; add a delay that honors retry-after. The SDK's own client does that for POSTs, but only when the header is present.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume