Same prompt, four Sume video models: a Python script that logs cost

Submit one prompt to wan-3.0, minimax-h3, minimax-h3-max and seedance-2.5 on /v1/videos, poll each job, and print usage.cost per clip. Runnable as written.

5 min readSume
All posts

To compare video models fairly, send the same prompt, duration and aspect ratio to each Sume model id, wait for every job, and record usage.cost from the finished job. The script below does that for wan-3.0, minimax-h3, minimax-h3-max and seedance-2.5 at 480p and 6 seconds, using only the /v1/videos calls documented on the video generation page. Run it once, look at the four clips, then decide where to spend.

A 480p run is the cheap end of each row, so it tests the prompt and motion, not the final look.

Why these four at 480p

All four rows accept 480p, a 6-second duration and 16:9, so one request body is valid for each. Their ranges differ at the edges: wan-3.0 allows 2 to 30 seconds, the MiniMax rows 5 to 15, and seedance-2.5 4 to 30. A 6-second clip sits inside all three, and that is why the script uses it.

Settings that fit all four rows (Sume catalog, checked 2026-10-04)
Model idDuration rangeResolutionsAudio
wan-3.02 to 30 s480p, 720p, 1080pnative
minimax-h35 to 15 s480p, 768pnative stereo, always on
minimax-h3-max5 to 15 s480p, 768p, 1080pnative stereo, always on
seedance-2.54 to 30 s480p, 720p, 1080pnative

The script

It reads the key from SUME_API_KEY, gives each submit its own Idempotency-Key, polls every 20 seconds, and prints the status and cost. Stop it with Ctrl-C; jobs already submitted keep running and holding a reserve until they finish.

import os, time, requests

BASE = "https://api.sume.com/v1/videos"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
PROMPT = "A potter shapes a bowl on a wheel, warm window light"
MODELS = ["wan-3.0", "minimax-h3", "minimax-h3-max", "seedance-2.5"]

jobs = {}
for m in MODELS:
    body = {"model": m, "prompt": PROMPT, "resolution": "480p",
            "duration": 6, "aspect_ratio": "16:9"}
    r = requests.post(BASE, json=body, timeout=60,
                      headers={**H, "Idempotency-Key": f"cmp-{m}-001"})
    r.raise_for_status()
    jobs[m] = r.json()["polling_url"]

while jobs:
    for m, url in list(jobs.items()):
        j = requests.get(url, headers=H, timeout=30).json()
        if j["status"] in ("completed", "failed", "cancelled"):
            print(m, j["status"], j.get("usage", {}).get("cost"))
            del jobs[m]
    time.sleep(20)

Reading the output

usage.cost is the Sume billable amount, per the Sume differences table. A failed job has no finished clip to price, and its reserve is released. Keep the four MP4s next to the printed costs and judge them blind.

  • Same prompt does not mean same take: no row accepts a seed, so each run is one sample.
  • The cheapest clip is not the best value if it needs three re-rolls.
  • A second run with new Idempotency-Keys is a second set of samples; reusing the key returns the original job.

Next step

After picking a row, move to 720p or 768p and a longer duration. See the Video Router page for per-model limits and Jobs and results for the status lifecycle. If you prefer a webhook to polling, callback_url takes an HTTPS address and the signature headers are described in Video generation.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume