Clip-type route table in Python: Sora use cases to Sume models
A 30-line Python route table maps ads, demos and teasers to a Sume model, size and length, refuses a length the model cannot make, and prints the dollar cost.

Keep a small route table in code that maps each clip type to a Sume model, resolution, aspect ratio and length, and a limits table that refuses a length the model cannot make. The script below prices 600 ads, 250 demos and 150 teasers and prints $600.00, $420.00 and $94.50. It stops with an error if you route a 12-second demo to a model that stops at 10 seconds.
After OpenAI removed the Videos API and the sora-2 family on 2026-09-24, with no replacement listed, a library tends to need several models, not one. A table in code makes that choice reviewable.
The table and the checker
The limits are from the Sume catalog: wan-3.0 takes 2 to 30 seconds, gemini-omni-flash-1.1 takes 3 to 10 and kling-3 takes 4 to 15. The cents are billable prices for each model, resolution and length in the same catalog. Only four combinations are listed here; add the ones your library uses.
LIMITS = {"wan-3.0": (2, 30), "gemini-omni-flash-1.1": (3, 10), "kling-3": (4, 15)}
CENTS = {
("wan-3.0", "720p", 8): 100,
("wan-3.0", "1080p", 12): 300,
("gemini-omni-flash-1.1", "720p", 5): 63,
("kling-3", "1080p", 12): 168,
}
ROUTES = {
"ad": ("wan-3.0", "720p", "9:16", 8),
"demo": ("kling-3", "1080p", "16:9", 12),
"teaser": ("gemini-omni-flash-1.1", "720p", "9:16", 5),
}
def plan(kind, count):
model, res, aspect, secs = ROUTES[kind]
lo, hi = LIMITS[model]
if not lo <= secs <= hi:
raise ValueError(f"{model} takes {lo}-{hi} s, not {secs}")
cents = CENTS[(model, res, secs)] * count
return {"model": model, "resolution": res, "aspect_ratio": aspect,
"duration": secs, "dollars": cents / 100}
for kind, n in (("ad", 600), ("demo", 250), ("teaser", 150)):
print(kind, plan(kind, n))
try:
ROUTES["demo"] = ("gemini-omni-flash-1.1", "1080p", "16:9", 12)
plan("demo", 1)
except ValueError as err:
print("refused:", err)
What the script prints
The first loop prints one dict per clip type. Ads: 600 clips x 100 cents on wan-3.0 at 720p and 8 seconds, so 60,000 cents or 600.0 dollars. Demos: 250 x 168 cents on kling-3 at 1080p and 12 seconds, silent, so 420.0 dollars. Teasers: 150 x 63 cents on gemini-omni-flash-1.1 at 720p and 5 seconds, so 94.5 dollars. The three lines total $1,114.50.
The last lines reroute the demo to Omni at 12 seconds and call the planner, which raises ValueError and prints refused: gemini-omni-flash-1.1 takes 3-10 s, not 12. That is the guard doing its job; a missing price would raise a KeyError in the same way, which is also what you want for an unlisted combination.
Why validate before you submit
A length outside the range of a model is a rejected request, not a clamp. Catching it in your own table means a bad route fails when you edit it, not after you queued 250 jobs and read 250 errors. The same check is the right place to refuse a resolution the model does not have, such as 720p on minimax-h3.
The cost function is also a budget check. Compare the dollars it prints with the balance before you start a run; Sume reserves the cost of each job at submit and fails the submit with 402 insufficient_credits if the balance cannot cover it.
Checking the table against the live catalog
Do not trust a copy of the numbers for long. GET /v1/videos/models returns the supported resolutions, aspect ratios, durations and pricing fields for each model, and the list prices can change. A test that loads the catalog and asserts that every route in the table is valid is a cheap guard to run in CI.
Keep the route table in version control, with the reason for each row in a comment. When a model is retired or its price changes, the diff shows which clip types are affected, which is what OpenAI's removal of the sora-2 models taught many teams to want.
- One row per clip type, not per prompt.
- Include the idempotency key scheme alongside the route.
- Fail the build when a route points at a model id missing from the catalog.
Sources
Related posts
More in Developers
- Video trim is async by default: mode sync waits 30 s, then poll
Video trim returns a job at once by default. Send mode sync to wait up to 30 s for a 200, else get 202 and poll status, then result. Never resubmit.
- Video trim end past the clip: trim_clamped_to_source and a short ad
If end is beyond the source, Sume video-trim clamps it and warns trim_clamped_to_source. Ask for 0-20 s of a 15 s clip and you get 15 s, which can break a spot.
- Video upscale hold: omit duration_seconds and Sume reserves 5 s
Sume video upscale reserves from duration_seconds, or 5 seconds when you omit it. Hold table for 5, 15 and 30 seconds at $0.009 per second and the 402 case.
- Vidu Q4 or LTX on Sume? Check the video model list first
Sume does not list Vidu or LTX in its video catalog as of 2026-10-08. Query GET /v1/videos/models and filter by id; a short script and the 12 ids it returns.
Written by Sume