Video Generation
ModelMax provides async video generation through a queue-based API. You submit a prompt, poll for status, then download the result.
This is different from chat completions — video generation can take minutes, so it uses a submit-and-poll pattern instead of synchronous responses.
Workflow overview
1. Submit POST /v1/queue/{model} → 202 + request_id
2. Poll GET .../requests/{id}/status → IN_QUEUE | IN_PROGRESS | COMPLETED | FAILED
3. Result GET .../requests/{id} → data URLs + usage
4. Download GET .../requests/{id}/content/0 → video/mp4 binary
Step 1: Submit a task
curl -X POST https://api.modelmax.io/v1/queue/veo-3 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $MODELMAX_API_KEY" \
-d '{
"prompt": "A golden retriever running through autumn leaves in slow motion"
}'
import requests
API_KEY = "your-api-key"
BASE_URL = "https://api.modelmax.io"
resp = requests.post(
f"{BASE_URL}/v1/queue/veo-3",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"prompt": "A golden retriever running through autumn leaves in slow motion"},
)
resp.raise_for_status()
task = resp.json()
print(f"Request ID: {task['request_id']}")
print(f"Status URL: {task['status_url']}")
const BASE_URL = "https://api.modelmax.io";
const API_KEY = "your-api-key";
const resp = await fetch(`${BASE_URL}/v1/queue/veo-3`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_KEY}`,
},
body: JSON.stringify({
prompt: "A golden retriever running through autumn leaves in slow motion",
}),
});
const task = await resp.json();
console.log("Request ID:", task.request_id);
Response (202 Accepted):
{
"request_id": "Z2VtaW5pOnZlby0zOjg6NzIwcDoxOm9wLTEyMzQ1",
"status": "IN_QUEUE",
"status_url": "/v1/queue/veo-3/requests/Z2Vt.../status",
"response_url": "/v1/queue/veo-3/requests/Z2Vt..."
}
Save the status_url and response_url from the submit response — they contain the full paths you need for polling.
Step 2: Poll for status
The status endpoint is lightweight and does not trigger billing. Poll it every 5 seconds.
curl https://api.modelmax.io/v1/queue/veo-3/requests/{request_id}/status \
-H "Authorization: Bearer $MODELMAX_API_KEY"
import time
while True:
status_resp = requests.get(
f"{BASE_URL}{task['status_url']}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
status = status_resp.json()
print(f"Status: {status['status']}")
if status["status"] in ("COMPLETED", "FAILED"):
break
time.sleep(5)
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
let status: string;
do {
await sleep(5000);
const statusResp = await fetch(`${BASE_URL}${task.status_url}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const statusData = await statusResp.json();
status = statusData.status;
console.log("Status:", status);
} while (status !== "COMPLETED" && status !== "FAILED");
Status values
| Status | Description |
|---|---|
IN_QUEUE | Task accepted, waiting to start |
IN_PROGRESS | Video is being generated |
COMPLETED | Video is ready to download |
FAILED | Generation failed (check error field) |
Step 3: Get the result
Once COMPLETED, fetch the full result to get download URLs. This triggers billing.
curl https://api.modelmax.io/v1/queue/veo-3/requests/{request_id} \
-H "Authorization: Bearer $MODELMAX_API_KEY"
result_resp = requests.get(
f"{BASE_URL}{task['response_url']}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
result = result_resp.json()
if result["status"] == "COMPLETED":
for i, video in enumerate(result["data"]):
print(f"Video {i}: {video['url']}")
const resultResp = await fetch(`${BASE_URL}${task.response_url}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const result = await resultResp.json();
if (result.status === "COMPLETED") {
for (const video of result.data) {
console.log("Download:", video.url);
}
}
Step 4: Download the video
The url in each data entry is a relative path. Fetch it to download the MP4 binary.
curl -o video.mp4 \
https://api.modelmax.io/v1/queue/veo-3/requests/{content_id}/content/0 \
-H "Authorization: Bearer $MODELMAX_API_KEY"
for i, video in enumerate(result["data"]):
video_resp = requests.get(
f"{BASE_URL}{video['url']}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
with open(f"video_{i}.mp4", "wb") as f:
f.write(video_resp.content)
print(f"Saved video_{i}.mp4")
import { writeFile } from "fs/promises";
for (let i = 0; i < result.data.length; i++) {
const videoResp = await fetch(`${BASE_URL}${result.data[i].url}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const buffer = Buffer.from(await videoResp.arrayBuffer());
await writeFile(`video_${i}.mp4`, buffer);
console.log(`Saved video_${i}.mp4`);
}
Complete example
Here's the full end-to-end flow in one script:
import requests
import time
API_KEY = "your-api-key"
BASE = "https://api.modelmax.io"
# 1. Submit
task = requests.post(
f"{BASE}/v1/queue/veo-3",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"prompt": "Timelapse of a flower blooming in a garden"},
).json()
print(f"Submitted: {task['request_id']}")
# 2. Poll
while True:
time.sleep(5)
status = requests.get(
f"{BASE}{task['status_url']}",
headers={"Authorization": f"Bearer {API_KEY}"},
).json()
print(f" Status: {status['status']}")
if status["status"] in ("COMPLETED", "FAILED"):
break
# 3. Result
result = requests.get(
f"{BASE}{task['response_url']}",
headers={"Authorization": f"Bearer {API_KEY}"},
).json()
# 4. Download
if result["status"] == "COMPLETED":
for i, v in enumerate(result["data"]):
data = requests.get(
f"{BASE}{v['url']}", headers={"Authorization": f"Bearer {API_KEY}"}
).content
with open(f"video_{i}.mp4", "wb") as f:
f.write(data)
print(f"Saved video_{i}.mp4 ({len(data)} bytes)")
else:
print(f"Failed: {result.get('error', 'unknown error')}")
Optional parameters
Pass a parameters object to control generation:
{
"prompt": "A drone shot of ocean waves",
"parameters": {
"aspect_ratio": "16:9",
"resolution": "1080p",
"duration_seconds": 6,
"generate_audio": true,
"negative_prompt": "blurry, low quality"
}
}
| Parameter | Type | Default | Description |
|---|---|---|---|
aspect_ratio | string | "16:9" | "16:9" or "9:16" |
resolution | string | "720p" | "720p", "1080p", or "4k" |
duration_seconds | integer | 8 | Video duration, max 8 |
generate_audio | boolean | true | Include audio track |
sample_count | integer | 1 | Number of videos (1–4) |
negative_prompt | string | — | What to avoid |
image | string | — | Base64 image for image-to-video |
Available models
| Model | Speed | Quality |
|---|---|---|
veo-3.1 | Standard | Highest |
veo-3.1-fast | Fast | High |
veo-3 | Standard | High |
veo-3-fast | Fast | Good |
veo-2 | Standard | Good |
