Grok Imagine video API: 15 s, 5 references, request-ID polling
xAI's video guide for grok-imagine-video-1.5 lists up to 15 seconds, up to 5 reference images and async polling by request ID. The same loop on Sume jobs.

xAI's guide, read 2026-10-03, describes grok-imagine-video-1.5 as a model that makes clips up to 15 seconds long, accepts up to 5 reference images, and runs asynchronously: you submit, get a request ID, then poll with that ID. Sume uses the same submit-then-poll shape, with a job id and a polling_url.
The vendor facts
Only three things come from the xAI page for this post.
- Model:
grok-imagine-video-1.5. - Limits: up to 15 seconds and up to 5 reference images.
- Pattern: asynchronous generation, polled by request ID.
The Sume equivalent
On Sume the loop is: POST /v1/videos, read id and polling_url from the 202 response, poll until the status is completed, then download from unsigned_urls[0]. Statuses are pending, in_progress, completed, failed and cancelled. Send an Idempotency-Key so a retried submit returns the original job instead of creating and billing a second one.
Reference images go in input_references; first or last frame images go in frame_images. If both are present, frame_images wins and the request is treated as image to video, which is easy to miss when you port a request that carried both.
A polling loop with a deadline
The Sume guide suggests a polling interval around 30 seconds. This version backs off and stops after a deadline, using only the standard library.
import json, os, time, urllib.request
KEY = os.environ["SUME_API_KEY"]
H = {"Authorization": "Bearer " + KEY, "Content-Type": "application/json",
"Idempotency-Key": "grok-port-001"}
def call(url, body=None):
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(url, data=data, headers=H)
with urllib.request.urlopen(req) as r:
return json.load(r)
job = call("https://api.sume.com/v1/videos",
{"model": "sume/auto", "prompt": "A paper boat drifting down a rain gutter",
"duration": 5, "aspect_ratio": "16:9"})
delay, deadline = 10, time.time() + 900
while time.time() < deadline:
s = call(job["polling_url"])
if s["status"] in ("completed", "failed", "cancelled"):
print(s["status"], s.get("unsigned_urls"))
break
time.sleep(delay)
delay = min(delay * 2, 60)Porting notes
Keep your request builder separate from your polling code. The builder maps your internal shot object to a vendor payload, and only that function should change when you switch providers. The poller, the storage step and the failure handling can stay the same.
Store the job id the moment the submit returns. If your process restarts mid-wait, the stored id lets you resume polling instead of paying for a duplicate.
Limits to compare
xAI allows 5 reference images. Sume's per-model limits differ, for example Gemini Omni Flash 1.1 takes up to 10 reference images and up to 3 reference videos of at most 3 seconds each, while the legacy Video 1.0 route takes 1-9 images. Do not carry one vendor's counts to another, and read supported_input_references for the model you pin.
Never resubmit a paid request because your poller timed out. The jobs guide says to keep polling the stored job id.
Sources
Related posts
More in Developers
- How long AI video vendors keep your file: Veo 2 days, Higgsfield 7+
Veo keeps videos two days, Higgsfield files at least seven, Sora Batch outputs were kept 24 hours. Retention facts and a download-on-complete script.
- How to get an AI video generation API key: Sume steps and gotchas
Create a workspace API key in the Sume dashboard, send it as one header, check it with GET /v1/me, and keep it on your server. Scopes are fixed at creation.
- Instagram Reels API: a 100-posts-per-24-hours publish budget
The Instagram content publishing API limits an account to 100 API-published posts per moving 24 hours. A tested Python queue that spreads batch output under it.
- Keep your Sora-style create_video() call: map it onto Sume
Sora's seconds, size and input_reference become duration, resolution plus aspect_ratio, and a first frame. Here is that map as a Python wrapper over Sume.
Written by Sume