Sume TypeScript SDK waitForJob: 20-minute timeout, job keeps billing

How @sume-com/sdk waitForJob polls a generation job, what SumeJobTimeoutError means, and why a client timeout does not cancel or refund the job.

3 min readSume
All posts

waitForJob in @sume-com/sdk polls /v1/jobs/:id until the job is terminal, with a default timeout of 20 minutes, a 2-second poll floor, and a longer interval whenever next_poll_after_seconds asks for one. If the timeout hits first it throws SumeJobTimeoutError, and the job keeps running and keeps billing, because the helper only stops your wait.

The SDK runs page lists the options; this post shows the shape of a production call and the one decision that matters on timeout.

Submit with fetch, wait with the SDK

The SDK client sends x-api-key only, so do not add an Authorization header to its calls. The raw submit below uses Bearer on its own request, which is fine. A /v1/videos job id is a job at /v1/jobs/{id}, which is what waitForJob reads.

import { createSumeClient, waitForJob, SumeJobTimeoutError } from "@sume-com/sdk";

const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });

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": "mug-push-in-001",
  },
  body: JSON.stringify({ model: "wan-3.0", prompt: "Push-in on a ceramic mug", duration: 5 }),
});
const { id } = await res.json();

try {
  const job = await waitForJob(id, {
    client,
    timeout: 25 * 60_000,
    onStatus: (status) => console.log(status),
  });
  console.log(job.status, job.result?.artifacts);
} catch (e) {
  if (e instanceof SumeJobTimeoutError) console.log("still running:", e.jobId);
  else throw e;
}

Behaviors worth knowing

  • Generated operations resolve with { data, error, response } and do not throw on an API error; the wait helpers do throw.
  • It resolves with the job record from /v1/jobs/:id, not /result, so a failed or canceled job gives you status and error directly.
  • The client retries 408, 429 and 5xx twice by default and retries a POST only when it carries an Idempotency-Key.
  • Pass an AbortSignal to stop waiting early; it ends the wait, not the job.

What to do on timeout

Store e.jobId. Read it again later with getApiJob, or cancel it with cancelApiJob if it has not started. Resubmitting the original request is the one wrong answer, since that pays for a second job.

Choosing between helpers

Use waitForJob for generation jobs, which live at /v1/jobs/:id. Use waitForRun for Action, Agent Completion and Format runs, and subscribeFormatRun when you want to create a Format run and wait for it in one call. A job id is not a run id, and the two cannot be swapped. When you can skip waiting entirely, a webhook with verifyWebhook is the better fit.

Settings that matter

  • timeout defaults to 20 minutes for jobs.
  • pollInterval defaults to 2 seconds and acts as a floor; a longer next_poll_after_seconds wins.
  • signal aborts the wait and the in-flight request.
  • The client adds jitter to polls so several waiters started together do not stay in phase.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume