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.

5 min readSume
All posts

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.

Limits that commonly break a ported request (docs.sume.com/models/video-router, read 2026-10-05)
ModelDurationsResolutionsAspect ratios
gemini-omni-flash-1.13-10 s360p, 720p, 1080p, 4K16:9, 9:16 only
seedance-24-15 s480p, 720p, 1080pincludes 1:1, 4:3, 21:9
seedance-2.54-30 s480p, 720p, 1080pread from catalog
wan-3.02-30 s480p, 720p, 1080pread from catalog
minimax-h35-15 s480p, 768p768p 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

All Developers posts

Written by Sume