Video Router or /v1/videos for ported Sora code?
Both routes create the same Sume video jobs with the same model ids. /v1/videos is the OpenRouter-style wire; /v1/video-router/generate is the older flat one.

For new code replacing a Sora call, use POST /v1/videos. The Video Router docs say new integrations should use it, and the video generation docs say the legacy /v1/video-router/* routes keep working unchanged and create the same jobs with the same model ids. The difference is the wire: Video Router returns Sume's { "data": ... } job envelope with flat image_url and reference_image_urls, while /v1/videos follows the OpenRouter field names.
The two wires side by side
Because the model vocabulary is shared, moving between them is a path-and-body change with no id remapping, as the docs put it.
| Area | /v1/videos | /v1/video-router/generate |
|---|---|---|
| Status | Preferred for new integrations | Available and unchanged |
| Response | OpenRouter-style: id, polling_url, status | Sume { data } job envelope |
| Images in | frame_images and input_references | image_url, reference_image_urls |
| Download | unsigned_urls and /content endpoint | Result from the job |
| Webhook field | callback_url | mode webhook with webhook_url |
| Idempotency-Key | Supported | Supported |
Which fits ported code
If your Sora wrapper already thinks in jobs with a polling URL, /v1/videos is the closer match: submit returns a job id and a polling_url, and statuses are pending, in_progress, completed, failed and cancelled. Note that the same job is also readable as a Sume job at GET /v1/jobs/{id}/status, where statuses are queued, processing, completed, failed and canceled. Pick one vocabulary and normalize at the edge, since the spelling of cancelled differs.
When Video Router is the right call
Keep Video Router if you already built against it, or if you use the Gemini Omni edit mode: the docs expose the video edit capability through the Video Router video_url field, with /v1/videos accepting video references. There is no pressure to move; the docs state it stays available and unchanged.
What to decide this week
Choose the route, write a thin client that hides the envelope difference, and read GET /v1/videos/models for limits. The API reference links the OpenAPI document that is the source of truth for exact fields.
Sources
Related posts
More in Developers
- Voice agent hand-off: ask for a clip, get an async Sume job
A live voice agent should not wait on a video render. Hand the request to an async Sume job, speak the job id back, and deliver the clip by poll or webhook.
- VS Code 1.140 shared MCP config files: what goes in the Sume entry
VS Code 1.140 lets MCP servers live in portable config files shared across Copilot tools. For Sume the entry is one URL, and no key belongs in the file.
- Abort waitForJob on SIGTERM, then resume from the stored job id
On a deploy, abort waitForJob with an AbortController on SIGTERM, keep the Sume job id, and resume the wait after restart. Aborting stops the wait, not the job.
- waitForJob throws on a failed poll: resume by job id in TypeScript
Unlike waitForRun, waitForJob has no transient-failure budget: one failed status read after the client's retries throws. Wrap it and resume by job id.
Written by Sume