OpenRouter: poll video every 30 s. Sume: obey next_poll_after_seconds
OpenRouter recommends a 30 second poll on video. Sume's jobs API returns next_poll_after_seconds, else backoff. A Python poller that does both.

OpenRouter recommends polling a video job every 30 seconds, and Sume's own /v1/videos example also sleeps 30 seconds, but Sume's jobs API can do better: its status response may include next_poll_after_seconds, which you should obey, with exponential backoff as the fallback. A poller that reads that field uses fewer requests than a fixed 30 second sleep and reacts sooner at the start.
OpenRouter's recommendation is from its video generation guide, read 2026-10-10. Sume's are from the Jobs and results and Videos API docs.
Two polling contracts
On OpenRouter you submit to POST /api/v1/videos, poll the polling_url, and download from unsigned_urls[0] when the job completes. On Sume's OpenRouter-compatible route the shapes match, and the example loop waits 30 seconds between polls.
Sume's job-level endpoint, GET /v1/jobs/{id}/status, is the better target for a new poller. Its envelope has the booleans terminal and result_ready, and the docs say to continue polling status_url, obey next_poll_after_seconds when present, and fall back to backoff.
| Question | OpenRouter | Sume |
|---|---|---|
| Where to poll | polling_url | polling_url on /v1/videos, or status_url on the jobs API |
| Suggested wait | 30 seconds | 30 seconds in the /v1/videos example; next_poll_after_seconds when the job envelope gives it |
| Stop condition | A completed or failed status | terminal is true |
| Result ready | unsigned_urls[0] | result_ready true, then GET result_url |
| Read budget | Not read from the page | Reads get 40 times the write budget per plan |
| Do not | Not read from the page | Submit a new paid job because a local timeout fired |
A poller that obeys both
The loop below starts with a short delay, uses the server's hint when present, and otherwise doubles its wait up to 30 seconds, which keeps it no more aggressive than the OpenRouter recommendation at steady state.
import time, requests
def wait(status_url, headers, deadline_s=1200):
delay, end = 3.0, time.time() + deadline_s
while time.time() < end:
r = requests.get(status_url, headers=headers, timeout=30)
r.raise_for_status()
s = r.json()
s = s.get("data", s)
if s.get("terminal"):
return s
hint = s.get("next_poll_after_seconds")
delay = float(hint) if hint else min(delay * 2, 30.0)
time.sleep(delay)
raise TimeoutError("deadline passed; keep the job id")Why the hint matters
Reads have their own bucket on Sume, forty times the write limit, so a polling loop will not block your submits, and a 429 names which bucket you hit in error.details.scope. Even so, a long fixed sleep wastes the first seconds of a short job, while a tight loop on a long job just burns requests. Honouring the hint lets the server tell you when to come back.
The deadline is client-side. For video, the Sume docs suggest 20 minutes is reasonable. When it passes, stop polling but keep the job id; the job may still finish and bill, so look at it again later instead of submitting a new one.
Mixing a webhook with the poll
The cheapest design is a webhook plus a slow sweep. Submit with a webhook URL, record the job id, and let a background task read the status of any job that is still open after a few minutes. The webhook handles the common case at no polling cost, and the sweep catches deliveries that never arrived. Sume's docs ask for exactly this: continue to poll as a backup.
If you move from OpenRouter, remember that the callback body changes shape on Sume, so the handler is not a drop-in. Sume signs the raw body with a timestamp, and your verifier must refuse an empty secret.
Sources
Related posts
More in Developers
- OpenRouter's video expired event has no Sume twin: one normalizer
OpenRouter sends completed, failed, cancelled and expired video events; Sume sends three job events. A Python normalizer and verifier for both.
- Pick the cheapest Sume image row for a ratio and 3 refs (Python)
A 24-line Python script reads GET /v1/images/models and the endpoints route, filters by aspect ratio and reference count, and sorts by billed price.
- Pick the highest resolution a Sume video model lists (Python)
Sume's catalog row is now the one resolution list for both video endpoints. A short Python helper reads supported_resolutions and steps down instead of failing.
- Port a fal queue submit and poll loop to Sume /v1/videos in Python
A fal queue client posts to queue.fal.run, polls a status URL and fetches a result. The Sume version is 21 lines of Python on /v1/videos. Field map, traps.
Written by Sume