Five status vocabularies on the Sume and OpenRouter video APIs

Sume job status, the queue-shaped field, /v1/videos status, webhook delivery status and OpenRouter status differ in spelling. One TypeScript map fixes it.

4 min readSume
All posts

A Sume video integration can see five different status vocabularies: the job status (queued, processing, completed, failed, canceled), the queue-shaped status field (IN_QUEUE and friends), the /v1/videos status (pending, in_progress, completed, failed, cancelled), the webhook delivery status, and, if you also call OpenRouter, its own list. Spelling differs, and so does the double-L in cancelled.

The vocabularies

The values come from Sume's Jobs and results, Errors, and Video generation pages, and from OpenRouter's video guide.

Status values by surface (vendor docs, read 2026-10-09)
SurfaceValuesNotes
Sume job (/v1/jobs/:id)queued, processing, completed, failed, canceledTerminal: completed, failed, canceled
Sume queue-shaped status fieldIN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELEDMaps one-to-one onto the job status; do not mix the two
Sume /v1/videospending, in_progress, completed, failed, cancelledSame job also visible at /v1/jobs/{id}
Sume webhook deliverypending, delivering, delivered, retrying, failed, exhaustedAbout the callback, not the job
OpenRouter poll statuspending, in_progress, completed, failedWebhook payloads also use cancelled and expired

Normalize once, at the edge

Map every value to your own small set as soon as it enters your code. The function throws on an unknown value, so a new status surfaces in a test and does not become an infinite poll. I ran this with Bun.

type Phase = "waiting" | "running" | "done" | "failed" | "canceled";

const PHASES: Record<string, Phase> = {
  queued: "waiting", pending: "waiting", IN_QUEUE: "waiting",
  processing: "running", in_progress: "running", IN_PROGRESS: "running",
  completed: "done", COMPLETED: "done",
  failed: "failed", FAILED: "failed",
  canceled: "canceled", cancelled: "canceled", CANCELED: "canceled",
};

export function phase(status: string): Phase {
  const mapped = PHASES[status];
  if (!mapped) throw new Error(`unknown job status: ${status}`);
  return mapped;
}

for (const s of ["queued", "pending", "in_progress", "cancelled", "COMPLETED"]) {
  console.log(s, "->", phase(s));
}

Two traps

First, do not use the webhook delivery status to decide whether a job finished. A delivery can be exhausted on a job that completed. Second, poll on the booleans terminal and result_ready, or on sume_status, but not on a mix of the queue-shaped status and sume_status. They always agree, but code that reads both invites drift.

A GET /v1/jobs/:id/result on a job that did not complete answers 409 job_not_completed. For failed and canceled jobs, read the failure from the job record.

Mapping rules

Map every vocabulary to a small internal set such as pending, running, done, failed and canceled, and keep the original string for logs. Spelling differs: /v1/videos uses cancelled, while Sume jobs use canceled. Failed and canceled job webhooks both carry the status ERROR, so branch on the event name, not the status.

Do not mix the queue-shaped field with the job status. They describe the same job in different terms, and a client that reads one and expects the other will get stuck.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume