/v1/videos canonical_slug: the stable model id to store
Store canonical_slug (or id) from GET /v1/videos/models, not the display name. On Sume ids are bare, like seedance-2, with no org prefix.

Pin the canonical_slug or id from GET /v1/videos/models, not the name. The display name ("Seedance 2.0") is for people. The slug (seedance-2) is what you send as model, and the Sume docs describe canonical_slug as the permanent model identifier.
One catalog row
The catalog row in the Sume docs looks like this. The id and canonical_slug are the same string, and Sume uses bare ids with no provider-org prefix.
| Field | Example value | What to do with it |
|---|---|---|
id | seedance-2 | Send as model in POST /v1/videos |
canonical_slug | seedance-2 | Store in your database as the pinned id |
name | Seedance 2.0 | Show in UI only |
created | 1767225600 | Sort or display; not an id |
hugging_face_id | null | Null in the docs example |
Why bare ids
The catalog is a projection of the Video Router catalog, so the ids match what POST /v1/video-router/generate takes. A client that used the legacy surface needs no id remapping.
OpenRouter publishes ids as org/slug. Sume does not: its published contract never has a provider-org prefix. If you port a client written from OpenRouter docs, replace such ids with the bare ids from this catalog.
List the live ids
This script prints every slug and name from the live catalog, so you can diff it against what you pinned.
import asyncio, os
import httpx
async def main():
headers = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
async with httpx.AsyncClient(base_url="https://api.sume.com", headers=headers) as c:
r = await c.get("/v1/videos/models")
r.raise_for_status()
for m in r.json()["data"]:
print(m["canonical_slug"], "|", m["name"])
asyncio.run(main())One exception
sume/auto is not in this list. It is a routing pseudo-model that the API accepts as model but does not list. Treat it as a separate value in your config.
Sources
Related posts
More in Developers
- /v1/videos status expired: in the enum, never sent by Sume
The /v1/videos status enum includes expired for OpenRouter compatibility, but Sume never emits it. Handle it as terminal anyway; five other statuses occur.
- /v1/videos id and generation_id are one Sume job id: store one
On Sume the id and generation_id in a /v1/videos poll are the same job id, unlike OpenRouter's two ids. Store one and reuse it on /v1/jobs routes.
- /v1/videos failed: 'Could not download an input media URL' fix
A /v1/videos job fails with 'Could not download an input media URL (image_url)' when Sume cannot fetch your input. Make the URL public https and resubmit.
- /v1/videos poll status: pending, in_progress, and the Sume job state
On /v1/videos, a Sume job reads queued as pending, processing as in_progress, canceled as cancelled. The full status mapping, and why expired never appears.
Written by Sume