Turn a shot list into Gemini Omni requests: Python on Sume
Submit every line of a shot list as its own Omni job with stable Idempotency-Keys, then poll them in one pass. Runnable Python and the cost of a 3-shot list.

A shot list becomes Omni requests by sending one POST /v1/videos per line, giving each a deterministic Idempotency-Key, and then polling all the job URLs in a single loop. Because Omni caps a clip at 3 to 10 seconds in Sume's catalog, a film is always a list of short jobs; the list is the plan.
The script below needs only SUME_API_KEY in the environment and the requests package.
Shape the list so keys are stable
Key each shot by its number and a version string you bump on purpose, for example ad-v3-shot-02. If the process crashes and you rerun it, the same body with the same key returns the original job instead of a new charge. The Sume doc notes that reusing a key with a different body is a 409, so edit the version, not just the prompt, when you mean to re-roll.
The script
It submits all shots first so they run in parallel on Sume's side, then polls each polling URL every 15 seconds until none is pending or in progress.
import os, time, requests
BASE = 'https://api.sume.com/v1/videos'
H = {'Authorization': 'Bearer ' + os.environ['SUME_API_KEY']}
VERSION = 'ad-v1'
SHOTS = [
('Wide: a bakery storefront at sunrise, steam from the vents.', 6),
('Close-up: hands dust flour over dough, warm light.', 5),
('Medium: a baker slides a tray of loaves from the oven.', 6),
]
def main():
jobs = {}
for n, (prompt, secs) in enumerate(SHOTS, 1):
body = {'model': 'gemini-omni-flash-1.1', 'prompt': prompt,
'duration': secs, 'resolution': '720p', 'aspect_ratio': '16:9'}
r = requests.post(BASE, json=body, timeout=60,
headers={**H, 'Idempotency-Key': f'{VERSION}-shot-{n:02d}'})
r.raise_for_status()
jobs[n] = r.json()['polling_url']
done = {}
while len(done) < len(jobs):
time.sleep(15)
for n, url in jobs.items():
if n in done:
continue
s = requests.get(url, headers=H, timeout=60).json()
if s['status'] in ('completed', 'failed', 'cancelled'):
done[n] = s
for n in sorted(done):
print(n, done[n]['status'], done[n].get('unsigned_urls'))
main()What a 3-shot list costs
Sume bills list times 1.25 per second, rounded up to the cent per job, with fal list rates for Omni Flash 1.1 (recorded 2026-08-28) of $0.03, $0.10, $0.15 and $0.30 per second at 360p, 720p, 1080p and 4K. The script's three shots total 17 seconds (6 + 5 + 6).
| Resolution | Per second | Cost of 17 seconds across 3 jobs |
|---|---|---|
| 360p | $0.0375 | about $0.64 before per-job rounding |
| 720p | $0.125 | about $2.13 before per-job rounding |
| 1080p | $0.1875 | about $3.19 before per-job rounding |
Failure handling you should add
A failed poll carries an error string; a bad image URL, for example, reads as a download problem rather than a provider wrapper. Print it, fix the input, bump the version, and resubmit only that line. A 402 means the workspace balance is below the reserve, and a 429 means slow down; both are in the doc's error table. Prefer callback_url over polling once you run this from a server; see the related post on polling backoff.
Where the script goes next
Once the jobs are complete, the list of unsigned_urls is your shot order. Download each file, check the duration and the frame size, and join them with a Sume timeline if you want one file. All shots from one model share the same aspect ratio, so no crop is needed; mix models only after checking frame rates and ratios. Keep your SHOTS list in version control: the key is built from the version and the shot number, so the list is also your audit trail of what you ran and what you paid for.
Sources
Related posts
More in Developers
- Should my backend call Sume over hosted MCP or the REST API?
REST from a backend, hosted MCP from an agent client. Where they differ: auth, wait limits, REST-only Image 1.0 and Video 1.0, and write budgets.
- Retiring a webhook endpoint: Sume runs already carrying it still POST
Any run created with a webhook_url can POST when it ends, even after you decommission the endpoint. Retries run 10 times, and the receipt holds the real result.
- Speaking rate in words per minute from Sume STT word times (Python)
Compute words per minute for a recording from the words[] start and end times Sume STT returns, plus a per-minute pacing table. Offline Python, no API call.
- Speech to text API in Go: transcribe audio with net/http
Transcribe audio in Go using only the standard library: submit to Sume STT, poll the job and print the text. A 30-line program at one cent per audio minute.
Written by Sume