Sora replacement smoke test: one prompt, three Sume models, in Python
A short Python script that sends the same 5-second prompt to seedance-2.5, wan-3.0 and gemini-omni-flash-1.1 on Sume and prints status, cost and URLs.

To check which replacement fits a Sora-era prompt, send the identical request to a few candidates and compare status, cost and the saved file. The script below does that against three Sume catalog ids, seedance-2.5, wan-3.0 and gemini-omni-flash-1.1, using the documented submit, poll and download flow.
Why these three
Higgsfield's Sora migration guide, published October 3, lists Seedance 2.5, Kling 3.0 and Wan 3.0 as alternatives, noting Seedance 2.5 and Wan 3.0 at 30 seconds and 1080p. Sume's docs list seedance-2.5 at 4 to 30 seconds, wan-3.0 at 2 to 30 seconds and gemini-omni-flash-1.1 at 3 to 10 seconds with 360p to 4K. A 5-second clip is inside all three duration ranges, which makes it a fair first test. Check supported_resolutions for each id before you rely on 720p.
The script
It submits all three jobs first, so they run in parallel, then polls each one. It needs SUME_API_KEY in the environment and the requests package.
import os
import time
import requests
BASE = "https://api.sume.com/v1/videos"
AUTH = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
MODELS = ["seedance-2.5", "wan-3.0", "gemini-omni-flash-1.1"]
PROMPT = "A paper boat drifts down a rain-soaked street, slow tracking shot"
def submit(model):
body = {"model": model, "prompt": PROMPT, "duration": 5,
"resolution": "720p", "aspect_ratio": "16:9"}
headers = {**AUTH, "Idempotency-Key": f"smoke-{model}-001"}
r = requests.post(BASE, json=body, headers=headers)
r.raise_for_status()
return r.json()["polling_url"]
def wait(url):
while True:
job = requests.get(url, headers=AUTH).json()
if job["status"] in ("completed", "failed", "cancelled"):
return job
time.sleep(30)
urls = {m: submit(m) for m in MODELS}
for model, url in urls.items():
job = wait(url)
print(model, job["status"], job.get("usage", {}).get("cost"), job.get("unsigned_urls"))Reading the output
Each line prints the model, the final status, usage.cost and the download URLs. Compare three things:
- Status: a
failedline carries anerrorfield on the poll response; read it before you change anything. - Cost:
usage.costis the Sume billable amount; the balance is reserved on submit at provider list times 1.25. - File: download each URL with your key in the
Authorizationheader and watch the clips side by side.
Limits of a one-prompt test
One prompt says little about quality across your catalog. Use it to confirm that each model accepts your fields and returns a file, then run your real prompts. If a model rejects resolution or aspect_ratio, the 400 response is unsupported_parameter; check the model's entry in GET /v1/videos/models and adjust.
The script is safe to re-run. The fixed idempotency keys replay the original jobs, so change the suffix when you want fresh renders. See Jobs and results for status handling, including why a local timeout should never trigger a resubmit.
Sources
Related posts
More in Developers
- Sora files lived 1 hour: storing Sume job results
OpenAI's Sora 2 and Videos API shut down Sept 24, 2026, and videos were downloadable for 1 hour. Download and store Sume job results promptly.
- Sort your MCP tool allowlist: stable order keeps the prompt cache warm
MCP 2026-07-28 asks servers for ttlMs, cacheScope and a deterministic tool order. On the client, sort your media tool allowlist the same way. Python snippet.
- STT words array has spacing tokens: filter type word before you count
Word counts and captions go wrong because the words array can include spacing items. Filter by type, keep timings, and compute speaking rate correctly.
- FID retired Nov 1: keep a Sume generate button responsive
Vercel Speed Insights drops First Input Delay on November 1. A Sume generate button stays responsive if it submits async, gets a 202 and polls via your server.
Written by Sume