Sume /v1/videos says pending, /v1/jobs says queued: map both
/v1/videos uses pending and in_progress; /v1/jobs uses queued and processing; cancelled vs canceled. A mapping table and a JS helper to normalize both.

Sume exposes the same job under two status vocabularies. GET /v1/videos/{id} follows the OpenRouter shape: pending, in_progress, completed, failed, cancelled. GET /v1/jobs/{id}/status uses queued, processing, completed, failed, canceled. They describe one job, so map them once in a helper rather than branching on both.
The mapping
The jobs vocabulary is defined in the jobs guide, and the videos one in the video API doc. Note the spelling difference in the cancelled state: the videos route has two l letters, the jobs route one.
| /v1/videos | /v1/jobs | Terminal |
|---|---|---|
| pending | queued | No |
| in_progress | processing | No |
| completed | completed | Yes |
| failed | failed | Yes |
| cancelled | canceled | Yes |
Why both exist
/v1/videos was shaped so that clients written for the OpenRouter video docs work after changing the base URL and key. The shared jobs routes serve every Sume generation product, so they use Sume's own status names. A video created through /v1/videos can also be read through /v1/jobs/:id/status, which is useful when one monitor watches video, image and TTS jobs together.
A helper that hides the difference
Normalize on read, then the rest of your code uses one set of names.
const MAP = {
pending: 'queued',
in_progress: 'processing',
cancelled: 'canceled',
};
export const norm = (s) => MAP[s] ?? s;
export const isTerminal = (s) =>
['completed', 'failed', 'canceled'].includes(norm(s));Other differences worth knowing
The expired status exists in the /v1/videos enum for wire compatibility but is never emitted, because Sume does not expire jobs. On a video that failed, the poll response's error is the same public remap that sits behind the jobs status route, so you diagnose from the poll response and not from a raw worker error.
The completed video is downloaded from unsigned_urls[0] on the videos route. On the jobs route, read the artifacts from /v1/jobs/{id}/result.
Related posts
More in Developers
- Sume webhook and status poll race: never move a job row backwards
A late poll can say processing after the webhook already said completed. A rank-guarded SQLite update keeps a Sume job row from going backwards.
- Sume webhook five-minute replay window: reject stale deliveries
Sume signs timestamp.raw_body and advises a five-minute replay tolerance. Reject stale timestamps, refuse an empty secret, and keep job_id as the dedupe key.
- Sume webhook retried 10 times and stopped: recover the job anyway
Sume tries a webhook up to 10 times, 30 seconds apart, 10s timeout each. After that the job is still terminal. Poll status_url or call redeliver to recover.
- Sume webhook Redeliver vs Send test: which one replays a real job?
Send test posts a dummy webhook.test payload to a URL you type. Redeliver re-posts a real job's terminal event with a fresh signature. API routes for both.
Written by Sume