Edit a video with a prompt API: Python script for Omni Flash 1.1
Send a clip and a sentence to POST /v1/video-router/generate with gemini-omni-flash-1.1 and video_url, poll the job, read the result. Stdlib Python.

To edit a video with a text prompt over an API on Sume, POST the source clip as video_url and your instruction as prompt to /v1/video-router/generate with model: "gemini-omni-flash-1.1". The script below submits that request, polls the job until it is terminal, and prints the result. It uses only the Python standard library.
Which route takes an edit
Google's Gemini API guide names Gemini Omni Flash as its default video model and describes it as a model for video generation and conversational video editing. Sume exposes the edit mode through the Video Router route, not through the OpenRouter-shaped /v1/videos body, which is why the path below is /video-router/generate.
The script
Router responses use Sume's { "data": ... } envelope, so the script unwraps it. The job id is read defensively from the usual names, because this post only relies on what the jobs docs promise: a job id comes back on submit, and GET /v1/jobs/{id}/status and /result read it.
import json, os, time, urllib.request
BASE = "https://api.sume.com/v1"
KEY = os.environ["SUME_API_KEY"]
def call(method, path, body=None, extra=None):
headers = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json", **(extra or {})}
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(BASE + path, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=60) as r:
out = json.load(r)
return out.get("data", out)
job = call("POST", "/video-router/generate", {
"model": "gemini-omni-flash-1.1",
"prompt": "Replace the bottle with an apple. Keep everything else the same.",
"video_url": "https://example.com/clip.mp4",
"resolution": "720p",
"mode": "async",
}, {"Idempotency-Key": "edit-demo-001"})
job_id = job.get("request_id") or job.get("job_id") or job.get("id")
delay = 5
while True:
status = call("GET", f"/jobs/{job_id}/status")
if status.get("terminal") or status.get("status") in ("completed", "failed", "canceled"):
break
time.sleep(delay)
delay = min(delay * 2, 60)
print(status.get("status"))
if status.get("status") == "completed":
print(json.dumps(call("GET", f"/jobs/{job_id}/result"), indent=2))What to leave out
Keep the request small. video_url is the edit source and cannot be sent with image_url, end_image_url or any reference_*_urls. Do not send aspect_ratio, which is a 400 on edit, and do not send duration expecting it to cut the clip: the source sets the output. resolution is optional and defaults to 720p.
| Field | Edit mode |
|---|---|
video_url | Required: the source clip |
prompt | The edit instruction |
resolution | Optional: 360p, 720p, 1080p or 4K; default 720p |
aspect_ratio | 400 if sent |
generate_audio: false | 400: native audio is always on |
Sources
Related posts
More in Developers
- Effect 4.0.4 retryTransient honors Retry-After: key your Sume submit
Effect 4.0.4 makes HttpClient.retryTransient honor Retry-After, so a Sume 429 waits as told. It also retries POST on 5xx, so send an Idempotency-Key.
- Which fps to set: TikTok 23-60, YouTube list, Sume's 24/25/30/60
Sume Timeline fps can be 24, 25, 30 or 60, and every one is in TikTok's 23 to 60 window and on YouTube's list. Leave fps unset to match your sources.
- Gemini Omni edit returns 400: the five field mistakes on Sume
A video_url edit on gemini-omni-flash-1.1 fails with 400 when you add aspect_ratio, generate_audio false, bitrate_mode, reference audio, or other media. Fixes.
- Generate 100 images with the Sume Image API: async jobs and polling
Submit each image with mode async, collect job ids, then poll status. Each job bills only if it completes; failed jobs use no credits.
Written by Sume