Pick a video model from GET /v1/videos/models, not a constant
A new video model should not need a redeploy. Filter the Sume catalog by resolution, duration, audio and frame inputs at runtime, and survive a withdrawn model.

Read the model list from GET /v1/videos/models at runtime and filter it by what the request needs, instead of hard-coding a model id in your code. Each catalog row says which resolutions, aspect ratios and durations the model supports, whether it takes first or last frames, which reference types it accepts, and whether it generates audio. When a new model arrives or an old one is withdrawn, a pipeline that filters the list needs no deploy. A pipeline with a constant breaks, or never benefits.
What the catalog tells you
The video generation docs describe the response: a data array where each model has id, supported_resolutions, supported_aspect_ratios, supported_durations, supported_frame_images, supported_input_references, generate_audio and pricing_skus. Those are exactly the fields a request validator needs. Sume validates against the same catalog, so an unsupported combination returns a 400 rather than silently dropping a field.
Two other facts matter for a router. A model id that is not in the catalog gives 404 model_not_found. And sume/auto exists as a pseudo-model for when you want Sume to pick; use it when you do not need to control which model runs, and the filter below when you do.
A runtime filter
The function checks a request's resolution, duration, audio need and first-frame need against each row and returns the ids that fit. The sample catalog is trimmed from the docs plus an invented future-model-x row to show a model appearing without code changes; fetch the real list in production, cache it for a few minutes, and refresh on a 404 model_not_found. It runs as-is on Python 3.
catalog = {"data": [
{"id": "seedance-2", "supported_resolutions": ["480p", "720p", "1080p"],
"supported_durations": list(range(4, 16)), "supported_frame_images": ["first_frame", "last_frame"],
"supported_input_references": ["image_url", "video_url", "audio_url"], "generate_audio": True},
{"id": "future-model-x", "supported_resolutions": ["1080p"],
"supported_durations": [3, 4, 5], "supported_frame_images": [],
"supported_input_references": [], "generate_audio": False},
]}
def candidates(models, resolution, seconds, needs_audio=False, first_frame=False):
out = []
for m in models:
ok = resolution in m["supported_resolutions"] and seconds in m["supported_durations"]
ok = ok and (m["generate_audio"] or not needs_audio)
ok = ok and ("first_frame" in m["supported_frame_images"] or not first_frame)
if ok:
out.append(m["id"])
return out
print(candidates(catalog["data"], "1080p", 5))
print(candidates(catalog["data"], "1080p", 12, needs_audio=True))
print(candidates(catalog["data"], "1080p", 4, first_frame=True))Add price and a stable fallback
Capability is the first filter and price the second. The catalog carries pricing_skus per model; sort the candidates by it, or by your own preference list, and take the first. Keep a short ordered fallback of ids you have tested, and fall to sume/auto when none of them fits, so a withdrawn model degrades to a slightly different clip rather than an outage.
Do not cache forever. A model that was in the list yesterday may not be today, and a cached id that now returns model_not_found is a 404 you can catch once, refresh the list on, and retry with a new choice. A 404 at create means nothing ran and nothing was charged.
| Catalog field | Use | Effect |
|---|---|---|
| supported_resolutions | Resolution you need | Drop models without it |
| supported_durations | Clip length | Drop models that cannot do it |
| generate_audio | Audio needed | Drop silent models |
| supported_frame_images | first_frame or last_frame | Needed for i2v with a pinned start |
| supported_input_references | image, video or audio refs | Needed for reference-to-video |
| pricing_skus | Cost ordering | Sort remaining candidates |
Test the filter with fixtures
Keep a snapshot of the catalog in your test fixtures, plus a handful of requests with known good answers. When a launch adds a row, add it to the snapshot and run the tests; you learn in a minute whether your routing rules handle it. That is a better way to adopt new models than editing constants on launch day.
Respect model-specific limits
Capability filters are necessary but not sufficient. Some models have source-clip rules that a duration filter cannot express: for example a video-to-video recast model works on a supplied source clip of 5 to 30 seconds with one to four reference images, which is a different input shape from text-to-video. If your pipeline mixes modes, filter on the input fields the catalog lists (supported_frame_images, supported_input_references) and keep a separate branch for edit-style models rather than forcing them through the same request builder.
Sources
Related posts
More in Developers
- Pocket TTS API: run it yourself or call a hosted TTS API
Kyutai's Pocket TTS installs with pip and serves from localhost. If you want a hosted API with job URLs instead, here is the Sume request and what changes.
- Debug an MCP OAuth handshake in Postman against Sume's server
Postman can step through an OAuth 2.1 MCP handshake. Use it to find where a Sume connection breaks before you blame the agent client.
- Prefect 3 task retries for a Sume job: same Idempotency-Key
Retry a Sume image job in Prefect 3 without paying twice: a tested flow with retry_condition_fn, delay list and an order-derived idempotency key.
- Preflight an image request from Sume capability descriptors
Read supported_parameters from GET /v1/images/models and reject unsupported fields, enum values and out-of-range counts before a paid call returns a 400.
Written by Sume