Background texture

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

StatusDescription
IN_QUEUETask accepted, waiting to start
IN_PROGRESSVideo is being generated
COMPLETEDVideo is ready to download
FAILEDGeneration 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"
  }
}
ParameterTypeDefaultDescription
aspect_ratiostring"16:9""16:9" or "9:16"
resolutionstring"720p""720p", "1080p", or "4k"
duration_secondsinteger8Video duration, max 8
generate_audiobooleantrueInclude audio track
sample_countinteger1Number of videos (1–4)
negative_promptstringWhat to avoid
imagestringBase64 image for image-to-video

Available models

ModelSpeedQuality
veo-3.1StandardHighest
veo-3.1-fastFastHigh
veo-3StandardHigh
veo-3-fastFastGood
veo-2StandardGood