A /v1/videos id is a Sume job id: poll /v1/jobs for more (Python)
POST /v1/videos returns an id that is also a Sume job id. Poll GET /v1/jobs/{id}/status for terminal and next_poll_after_seconds, and cancel with /v1/jobs.

POST /v1/videos answers 202 with a bare OpenRouter-style object: id, polling_url, status and model. It is natural to poll polling_url and stop there. But the id is not a separate video handle. It is the Sume job id, the same one the Jobs API uses, which is why the poll response also repeats it as generation_id.
That means every job route accepts it, and some of them tell you more than the OpenRouter-shaped poll does. The video poll gives you pending, in_progress, completed, failed or cancelled. The job status route gives you a terminal boolean, a result_ready flag and a next_poll_after_seconds hint.
Which route for which job
| Need | Route |
|---|---|
| Poll in OpenRouter's shape | GET /v1/videos/{id} |
| Poll with terminal and a wait hint | GET /v1/jobs/{id}/status |
| Download the video | GET /v1/videos/{id}/content?index=0, a 302 redirect |
| Read the final job record and error | GET /v1/jobs/{id} |
| Ask for cancellation | POST /v1/jobs/{id}/cancel |
| Read events | GET /v1/jobs/{id}/events |
Poll through the Jobs API
The sample submits a Recast job through /v1/videos, then loops on /v1/jobs/{id}/status. The status routes wrap their response in data, unlike the video routes. The loop stops on terminal, and sleeps at least 2 seconds or whatever next_poll_after_seconds says. The standard library is enough.
import json, os, time, urllib.request
BASE = "https://api.sume.com/v1"
HEAD = {"x-api-key": os.environ["SUME_API_KEY"], "Content-Type": "application/json"}
def call(path: str, body: dict | None = None) -> dict:
data = json.dumps(body).encode() if body else None
req = urllib.request.Request(BASE + path, data, HEAD)
with urllib.request.urlopen(req, timeout=60) as r:
return json.load(r)
video = call("/videos", {
"model": "h3-max-recast",
"input_references": [
{"type": "video_url", "video_url": {"url": "https://example.com/source.mp4"}},
{"type": "image_url", "image_url": {"url": "https://example.com/host.jpg"}},
],
})
job_id = video["id"] # the same id every /v1/jobs route takes
while True:
s = call(f"/jobs/{job_id}/status")["data"]
print(s["sume_status"], s.get("next_poll_after_seconds"))
if s["terminal"]:
break
time.sleep(max(2.0, s.get("next_poll_after_seconds") or 0))
print("result:", s["result_url"])Why the hint beats a fixed sleep
- A queued job can wait behind your workspace's concurrency limit. Polling at a fixed 30 seconds is either too slow for a short job or wasteful for a queued one, and the hint tracks the job's own state.
terminalis true forcompleted,failedandcanceled. Checksume_statusbefore you fetch the result, and readGET /v1/jobs/{id}for the error when it is notcompleted.- Status reads count against your read budget, which defaults to 40 times the write budget, so a 2-second floor keeps a pool of jobs well inside it.
- The cancel route only works before generation starts. A running job returns
cancelable: falseand finishes, so check that flag first.
The status fields and the cancel rule are in the jobs guide. The OpenRouter-shaped routes and their statuses are in the videos docs.
Sources
Related posts
More in Developers
- Virtual try-on API: which Sume call returns an image, which a video
Need a try-on photo or a try-on clip? On Sume the two catalog try-on Formats return video; a still comes from the image API. The table, plus one call for each.
- Unit-test a Sume submit-and-poll loop in Vitest with fake replies
Test a Sume polling loop without spending credits: inject the sleep, replay queued then completed replies, and assert next_poll_after_seconds is honored.
- Voiceover longer than the video: speed up, trim or lengthen picture
A Sume TTS voiceover runs 35 seconds over a 30-second video. Compare speed up to 1.5x, a shorter script or a longer Timeline slot, with cost and a Python check.
- VS Code chat.mcp.autostart newAndOutdated: Sume's first run
VS Code can start MCP servers automatically when their config changes. Learn the autostart modes and the trust dialog before you add Sume's hosted server.
Written by Sume