waitForRun or waitForJob? Pick by which Sume endpoint made the id
A Sume run id cannot be read as a job id. Which create endpoint made your id decides waitForRun or waitForJob, with a TypeScript example of each.

Use waitForJob when the id came from a generation endpoint such as POST /v1/image-1.0/generate or POST /v1/video-1.0/generate. Use waitForRun when the id came from a Format, Action, or Agent run. Sume says you cannot use a job id as a run id, or a run id as a job id, so a wrong pick shows up as a failed read, not as a slow one.
Both helpers ship in @sume-com/sdk 0.2.0. They look alike, but they poll different URLs and they take different options.
Decide by the create call
The table is from the Waiting for runs and jobs page, read 2026-10-09.
| Id came from | Surface | Poll path | Helper | Default timeout |
|---|---|---|---|---|
POST /v1/formats/.../runs | Format run | /v1/format-runs/{id} | waitForRun with family: "format" | 10 minutes |
| Action run | Action run | /v1/action-runs/{id} | waitForRun with family: "action" | 10 minutes |
| Agent run | Agent run | /v1/agent-runs/{id} | waitForRun with family: "agent" | 10 minutes |
POST /v1/image-1.0/generate, /v1/video-1.0/generate, Avatar routes | Generation job | /v1/jobs/{id} | waitForJob | 20 minutes |
subscribeFormatRun | Format run (create and wait) | /v1/format-runs/{id} | The helper itself | 20 minutes |
What differs in the code
family is required on waitForRun and the helper cannot infer it, because a run id does not show its surface. waitForJob has no such option. It also treats pollInterval as a floor: when next_poll_after_seconds in the status payload asks for longer, that wins. Pass client to both, since the module default has no base URL or key.
import { createSumeClient, generateVideoV1, waitForJob, waitForRun } from "@sume-com/sdk";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
// Generation job: the id is request_id from the submit response.
const { data, error } = await generateVideoV1({
client,
headers: { "idempotency-key": crypto.randomUUID() },
body: { prompt: "Slow push-in on a ceramic mug", mode: "async" },
});
if (error) throw new Error(JSON.stringify(error));
const job = await waitForJob(data!.data.request_id, { client });
console.log(job.status, job.result.artifacts);
// Format run: you must say which family the id belongs to.
declare const runId: string;
const run = await waitForRun(runId, { client, family: "format" });
console.log(run.status, run.primary_output_url);What each one returns on failure
Neither helper treats a terminal failure as an exception. waitForJob resolves with the record from /v1/jobs/{id}, not from /result, because for failed and canceled jobs /result answers 409 job_not_completed and there would be nothing to hand back. Read status, result, and error from the record.
The helpers do throw on timeouts and request errors: SumeRunTimeoutError and SumeRunRequestError for runs, SumeJobTimeoutError and SumeJobRequestError for jobs. A timeout does not cancel the work. The job keeps running and keeps billing, so store the id, read it again later, or cancel it.
A quick check helps when you inherit code with a bare id. Look at where it was stored: an id saved from a /v1/jobs response is a job id, and an id saved from a *-runs response is a run id. If you cannot tell, read the id from each surface once, and expect a not-found from the wrong one. Do not guess a family in production code; keep the family next to the id in your own table.
If you can skip the wait, do. Both the runs page and the jobs page recommend webhooks for production, and the SDK has no event stream today: subscribe there means create, then poll.
Sources
Related posts
More in Developers
- Wan 3.0 reference clips: four 4-second videos break the 15 s cap
Wan 3.0 accepts up to 5 reference videos totalling 15 seconds at 16 fps or more. Four 4-second clips total 16 seconds and fail; three 5-second clips pass.
- wave_size_hint on an empty workspace: Free 4, Pro 18, Startup 36
What generation_limits.wave_size_hint returns before any job is queued, by Sume plan, with the arithmetic and a Python check you can run.
- Which AI video models on Sume make their own audio track
Gemini Omni Flash 1.1 always generates audio and rejects generate_audio false; MiniMax H3 Max has native stereo audio; Seedance 2.0 reports generate_audio true.
- Which id to send Sume support: req_, job_, arun_ or agrun_
Error bodies carry req_ ids; jobs have job_; Format and Action runs arun_; Agent Completions agrun_. Which to share with support, and what never to paste.
Written by Sume