Check duration, resolution, ratio against /v1/videos/models in Node
A Sora-era request will not fit every Sume model. A Node script reads GET /v1/videos/models and lists what the model rejects before you pay for a job.

Sume's GET /v1/videos/models returns, for each model, supported_durations, supported_resolutions, supported_aspect_ratios, supported_frame_images and supported_input_references, so a request can be checked against the model before it is submitted. The Node script below does that for one model and prints every mismatch. Run it in CI or in a pre-submit hook on a ported Sora client.
The docs are direct that limits are different for each model: gemini-omni-flash-1.1 takes 3 to 10 seconds, seedance-2.5 takes 4 to 30, wan-3.0 takes 2 to 30. A duration that worked on one backend can fail on the next, and the catalog is the place to find out which.
The script
It needs Node 18 or later for fetch, and reads the key from the environment. It treats an empty list as no constraint so models without a duration or ratio (such as edit-only ones) do not report false failures.
const MODELS_URL = "https://api.sume.com/v1/videos/models";
async function main() {
const key = process.env.SUME_API_KEY;
if (!key) throw new Error("SUME_API_KEY is not set");
const res = await fetch(MODELS_URL, { headers: { Authorization: `Bearer ${key}` } });
if (!res.ok) throw new Error(`models request failed: ${res.status}`);
const { data } = await res.json();
const req = { model: "gemini-omni-flash-1.1", duration: 12,
resolution: "720p", aspect_ratio: "9:16" };
const m = data.find((x) => x.id === req.model);
if (!m) throw new Error(`unknown model ${req.model}`);
const problems = [];
const check = (field, list, value) => {
if (list && list.length && !list.includes(value)) {
problems.push(`${field} ${value} not in [${list.join(", ")}]`);
}
};
check("duration", m.supported_durations, req.duration);
check("resolution", m.supported_resolutions, req.resolution);
check("aspect_ratio", m.supported_aspect_ratios, req.aspect_ratio);
console.log(problems.length ? problems.join("\n") : "request fits the catalog");
}
main().catch((e) => { console.error(e.message); process.exit(1); });What the example does
With duration: 12 against gemini-omni-flash-1.1, the script reports that 12 is outside the 3 to 10 second list, and nothing is submitted. Change the model to seedance-2.5 and 12 passes. The point is not the specific verdict, which comes from live data, but that the check costs one free GET.
Fields to know when you port
| Old-style idea | Sume field | Checked against |
|---|---|---|
| Length in seconds | duration (integer) | supported_durations |
| Output size | resolution + aspect_ratio | supported_resolutions, supported_aspect_ratios |
| Exact pixel size | size | Not accepted: 400 unsupported_parameter on v1 models |
| Starting image | frame_images with frame_type | supported_frame_images |
| Style references | input_references | supported_input_references |
| Audio on or off | generate_audio | generate_audio flag per model |
Keep it honest
A catalog check does not replace reading the error field on a failed job. Reference images must be public HTTPS URLs in supported formats, and prompts can be refused by a model's guidelines; neither shows up in the catalog. What the check removes is the cheap class of failure: a number that was never going to fit.
Cache the response briefly rather than fetching it per request, and re-read it when you add a model to a fallback list.
Wire it into a build
Run the script as a CI step with a read-only key kept in the environment, and fail the build when the problem list is non-empty. If you keep a fallback model, loop the same check over each model in the chain, so a config change that breaks the second backend fails before it reaches production.
Extend req to match what your app really sends. A request that adds frame_images can also be checked: confirm each frame_type you use appears in supported_frame_images, and each reference type appears in supported_input_references. The docs say a model accepts a reference type only if the list includes it, so this is a direct test, not a guess.
One more field is worth reading: generate_audio. If your pipeline needs a silent clip and the model reports no way to control it, the check should flag that rather than let a track appear in your output.
Sources
Related posts
More in Developers
- Check video model limits before you submit: GET /v1/videos/models
Models differ on length, resolution and references. Read GET /v1/videos/models and validate a request before a paid submit, with a Python preflight.
- Check GET /v1/videos/models before you pay: a Python validator
Read GET /v1/videos/models and reject bad duration, resolution or audio flags in Python before POST /v1/videos. Fewer 400s, no paid retries.
- Claude Code allowedMcpServers: the serverUrl rule for mcp.sume.com
Allow only Sume's hosted MCP endpoint in Claude Code managed settings with an allowedMcpServers serverUrl entry, and what the rule does not control.
- claude mcp add --header Bearer: a Sume API key for CI runs
For unattended Claude Code runs, pass a Sume API key as a Bearer header. That session sees every tool, so cap spend and send idempotency keys.
Written by Sume