Check a video request against the Sume catalog before the 400
Sume returns 400 unsupported_capability for unlisted values. A Python pre-flight reads GET /v1/videos/models and flags a bad duration or ratio first.

Ported Sora requests fail in one predictable way: a value the new model does not list. Sume answers with 400 unsupported_capability and does not bill, so the fix is cheap, but a nightly batch that hits 200 of them wastes an hour. A pre-flight that reads GET /v1/videos/models and compares duration, resolution and aspect_ratio against the model's own lists catches them before submit.
OpenAI removed the Videos API and the sora-2 ids on 2026-09-24 and named no replacement, so every request you send now is a translation. The catalog is the contract to translate into.
What the catalog tells you
Each row in the data array carries supported_durations, supported_resolutions, supported_aspect_ratios, supported_frame_images, supported_input_references and a seed flag. Sume's docs state that the catalog controls validation: if the model does not advertise a value, the request gets a 400 and the API does not silently drop the field.
Two more rejections are model-independent. size and seed return 400 unsupported_parameter on every v1 model, so a request translated from a pixel size or a seeded call fails everywhere until you remove them.
| Model | Durations | Resolutions | Aspect ratios |
|---|---|---|---|
| gemini-omni-flash-1.1 | 3-10 s | 360p, 720p, 1080p, 4K | 16:9, 9:16 only |
| seedance-2 | 4-15 s | 480p, 720p, 1080p | includes 1:1, 4:3, 21:9 |
| seedance-2.5 | 4-30 s | 480p, 720p, 1080p | read from catalog |
| wan-3.0 | 2-30 s | 480p, 720p, 1080p | read from catalog |
| minimax-h3 | 5-15 s | 480p, 768p | 768p is native; 720p is not accepted |
The pre-flight script
The script loads the catalog once, then checks a request against any model id. The demo request is a typical 12-second, square, 1080p ask. Run it and each model prints either ok or the exact field and list that would have failed.
import os, requests
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
r = requests.get("https://api.sume.com/v1/videos/models", headers=H, timeout=30)
r.raise_for_status()
CATALOG = {m["id"]: m for m in r.json()["data"]}
def problems(model_id, req):
m = CATALOG[model_id]
out = []
for key in ("seed", "size"):
if key in req:
out.append(f"{key} is rejected with 400 on every model")
checks = (("duration", "supported_durations"),
("resolution", "supported_resolutions"),
("aspect_ratio", "supported_aspect_ratios"))
for field, listed in checks:
if field in req and req[field] not in (m.get(listed) or []):
out.append(f"{field}={req[field]!r} not in {m.get(listed)}")
return out
old_style = {"duration": 12, "resolution": "1080p", "aspect_ratio": "1:1"}
for mid in CATALOG:
print(mid, problems(mid, old_style) or "ok")
Reading the output
Against that demo request, gemini-omni-flash-1.1 should report problems on all three fields, because its window is 3 to 10 seconds and it accepts only 16:9 and 9:16. seedance-2 should print ok: 12 seconds is inside its 4 to 15 range, and 1080p and 1:1 are both listed for it. The script does not hard-code that; it reads the live lists, so it stays right when the catalog changes.
What the pre-flight cannot see
It does not check audio. Gemini Omni Flash 1.1 always produces synced audio and the API rejects generate_audio: false, but the catalog's generate_audio flag only says a model can make audio, not that it cannot be turned off. It also does not check reference limits such as at most 10 images and 3 short clips on Omni. Keep those in your adapter.
Treat a pre-flight failure as a routing decision, not an error: try the next model in your fallback list, or shorten the clip. The 400 from the API remains the final authority, so keep handling it.
Sources
Related posts
More in Developers
- Check each shot against /v1/videos/models before submit: Python
A short Python check tests each shot's duration, resolution and ratio against GET /v1/videos/models fields, so a bad shot fails before it is billed.
- Check an Ideogram 4.5 edit left the rest of the image alone (Python)
Diff the source and the Ideogram 4.5 edit with Pillow, count changed pixels outside your text box, and fail the pass before it enters a chain. Code included.
- Check one video model first: GET /v1/video-router/models/{id}
Before you spend on a clip, read one model's limits with GET /v1/video-router/models/{model_id}. It returns capabilities and price, and 404s on an unknown id.
- Reference video job failed on download: check input URLs first
A Sume reference-to-video job fails when an input URL is not public. Python that HEAD-checks references before POST /v1/videos, and how to read the error.
Written by Sume