OpenRouter video expired status vs Sume job statuses
OpenRouter video jobs can end as expired, 'exceeded maximum time to live'. Sume has queued, processing, completed, failed and canceled. Map them in a client.

OpenRouter's video webhooks include a video.generation.expired event, and its docs describe the payload as a job that "exceeded maximum time to live". Sume has no expired status: its jobs are queued, processing, completed, failed, or canceled, and only the last three are terminal. If you port an OpenRouter client, map expired to a failure you can retry with a new request, because the page we fetched does not say how long the time to live is or whether an expired job is charged.
OpenRouter's facts are from its video generation guide, read on 2026-10-03. Sume's are from Jobs and results, generation admission, and webhooks.
What do we actually know about expired on OpenRouter?
Less than you would want. The guide lists four video webhook events: video.generation.completed, video.generation.failed, video.generation.cancelled, and video.generation.expired. The expired example carries the message that the job exceeded its maximum time to live.
The guide does not state the time limit, when in the lifecycle a job expires, whether unsigned URLs expire, or what happens to your charge. Do not write a billing rule for it from this page. If you depend on the answer, ask OpenRouter or test with a small job and read the usage figure in the response.
How do Sume's statuses line up?
Sume uses a smaller set. Polling on /v1/videos follows the OpenRouter-style wire with pending, in_progress, completed, failed, and cancelled, while the shared job endpoints at /v1/jobs/{id}/status use queued, processing, completed, failed, and canceled.
| OpenRouter event or status | Closest Sume state | Terminal on Sume |
|---|---|---|
| pending, in_progress | queued, processing | No |
| video.generation.completed | completed | Yes |
| video.generation.failed | failed | Yes |
| video.generation.cancelled | cancelled on /v1/videos, canceled on /v1/jobs | Yes |
| video.generation.expired | No equivalent; treat as failed and resubmit | Not applicable |
Why does a Sume job sit in queued instead of expiring?
On Sume, queued is a normal accepted state. The generation admission page says a valid job can wait for a workspace concurrency slot, and that when queue capacity is gone, new paid submissions fail with 429 queue_full rather than being accepted and later aged out. Queue capacity defaults to the larger of 3 and five times the concurrency limit.
So the failure you plan for on Sume is at submit (429 queue_full, 402 insufficient_credits), not a late time-to-live event. Your client should treat a submit-time 429 as retry with backoff and the same idempotency key.
How should a client handle the difference?
Write one function that turns a provider status into one of your own states, and keep the mapping in a table. Anything it does not recognize should fall to a manual-review state instead of silently counting as done:
TERMINAL_OK = {"completed"}
TERMINAL_RETRY = {"failed", "expired", "canceled", "cancelled"}
PENDING = {"pending", "in_progress", "queued", "processing"}
def classify(status: str) -> str:
if status in TERMINAL_OK:
return "done"
if status in TERMINAL_RETRY:
return "retry_with_new_key"
if status in PENDING:
return "keep_polling"
return "review"
assert classify("expired") == "retry_with_new_key"
assert classify("queued") == "keep_polling"
assert classify("mystery") == "review"What should you not do?
Do not resubmit a paid job just because a local process timed out. Sume's docs say to poll with backoff and stop on completed, failed, or canceled, and a resubmit with the same Idempotency-Key returns the original job rather than starting a second one.
Sume spells it cancelled on /v1/videos and canceled on /v1/jobs. Do not treat them as different outcomes in your database: pick one spelling at the boundary, normalize on the way in, and keep polling as the fallback for webhook events that never arrive.
How does this change your retry policy?
Split failures into two buckets. Buckets one is 'the request was bad': a failed job with a content or parameter error. Retrying the same payload will fail again, so fix the request first. Bucket two is 'the system ran out of time or room': an OpenRouter expired event, or a Sume job that ended failed for a reason that is not the request. A retry can help, but only with a new job or a fresh idempotency key, because on Sume a replay with the same Idempotency-Key returns the original job and its original outcome. A submit-time 503 is different: the docs say to retry that with the same key.
This is why the mapping function above sends expired to a retry with a new key. If you reused the old key on Sume you would get the first job back, not a second attempt.
What should you log for every terminal state?
Log the provider, the job id, the model id, the terminal status, the cost figure if one is returned, and the time from submit to terminal. Over a few weeks that gives you your own time-to-live curve, which is more useful than any vendor number: it tells you how long a normal job takes and how long is too long on your account.
Set your own client-side deadline from that curve, and cancel jobs that pass it. On Sume the cancel call can return 409 job_generation_already_started once generation has begun, so do not assume a cancel always stops spend.
Sources
Related posts
More in Comparisons
- OpenRouter video: frame_images and input_references together
Send both frame_images and input_references to an OpenRouter-style video API and Sume treats it as image-to-video. What changes, and how to split the fields.
- OpenRouter video unsigned_urls need an API key: Sume too
OpenRouter's unsigned_urls require your API key in the Authorization header, and so does Sume's content endpoint. Why a browser video tag fails and a safe fix.
- Pocket TTS voice cloning: a wav in, and what Sume does instead
Pocket TTS clones from a wav file you pass to --voice, with consent rules in its model card. Sume's API takes voice ids, not audio. Here is the difference.
- Replicate MCP discovery via server.json vs Sume's MCP URL
Replicate publishes /.well-known/mcp/server.json for the official MCP Registry. Sume documents one hosted MCP URL and OAuth metadata. How each client connects.
Written by Sume