Skip to main content

Overview

Veo 3.1 official API forwarding is now available through api.laozhang.ai. For new integrations, create a dedicated token, keep it in the default group, and set Billing mode to Pay-per-request. This page documents the API format, parameters, pricing, and code examples.

Pricing Advantage

Veo 3.1 official forwarding uses Pay-per-request billing with one unified price across supported duration and resolution combinations. Duration and resolution do not add extra charges. Based on public pricing from Google Gemini API Pricing, Google bills Veo 3.1 per second; the comparison below uses 8-second videos.
ModelLaoZhang priceGoogle 8s 1080pLower byGoogle 8s 4KLower by
veo-3.1-fast-generate-preview$0.3/call$0.9668.8%$2.4087.5%
veo-3.1-generate-preview$1.2/call$3.2062.5%$4.8075.0%
This route uses the same OpenAI Videos API style as Sora2 official forwarding:
StepMethodPathResponse
Create a video taskPOST/v1/videosJSON task object
Poll task statusGET/v1/videos/{id}JSON status object
Compatibility status pollingGET/v1/video/generations/{id}JSON status object
Download video outputGET/v1/videos/{id}/contentvideo/mp4 bytes
Use multipart/form-data when creating video tasks. Text-to-video and image-to-video both use the same /v1/videos task API.
Do not use the legacy Veo-3.1 sync route, legacy Chat Completions examples, or old model names such as veo-3.1, veo-3.1-fast, or veo-3.1-fl. The official-forward route only uses the model names and /v1/videos task API documented here.

Token Setup

SettingValue
Console entryToken management → create a new token
GroupDefault group
Billing modePay-per-request
RecommendationCreate a dedicated Veo 3.1 official-forward token for easier usage review
Veo 3.1 official forwarding uses the Pay-per-request billing mode across supported duration and resolution combinations. Duration and resolution do not add extra charges.

Supported Models

ModelPrice per callDescriptionBest for
veo-3.1-fast-generate-preview$0.3Veo 3.1 Fast preview modelQuick tests, drafts, cost-sensitive workflows
veo-3.1-generate-preview$1.2Veo 3.1 standard preview modelHigher-quality outputs, production assets, complex shots

Parameters

Core Parameters

ParameterTypeRequiredDescription
modelstringYesveo-3.1-fast-generate-preview or veo-3.1-generate-preview
promptstringYesVideo prompt
secondsstringNoDuration. For production integrations, use "8"
durationstringNoDuration. Keep it aligned with seconds, such as "8"
sizestringNoOutput size such as 1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160
resolutionstringNo720p, 1080p, or 4k
aspectRatiostringNo16:9 or 9:16
metadatastringNoJSON string. 4K requests must include {"durationSeconds":8,"resolution":"4k","aspectRatio":"16:9"}
negativePromptstringNoNegative prompt, such as blurry, watermark, distorted. Do not pass it for multi-reference or first/last-frame requests
seedstringNoRandom seed for similar repeatability
input_referencefileNoSingle initial image, or first frame for first/last-frame generation, uploaded as multipart/form-data
last_frame / lastFramefileNoFinal frame for first/last-frame generation. Must be used with input_reference
referenceImagesfileNoMulti-reference image field. Up to 3 images. Recommended field for production integrations
reference_image / reference_imagesfileNoCompatible multi-reference image fields. Up to 3 images
referenceType / reference_typestringNoReference image type. Use asset
Do not pass generateAudio. Veo 3 / Veo 3.1 models have native audio, but this API does not support audio toggling through generateAudio. Passing it may return INVALID_ARGUMENT. To guide audio content, describe dialogue, ambient sound, effects, or music style in the prompt.

Duration and Resolution

Use caseSuggested parameters
8s landscape 720pseconds="8", size="1280x720", resolution="720p", aspectRatio="16:9"
8s landscape 1080pseconds="8", size="1920x1080", resolution="1080p", aspectRatio="16:9"
8s portrait 1080pseconds="8", size="1080x1920", resolution="1080p", aspectRatio="9:16"
8s landscape 4Kseconds="8", duration="8", size="3840x2160", resolution="4k", aspectRatio="16:9", metadata='{"durationSeconds":8,"resolution":"4k","aspectRatio":"16:9"}'
Pass seconds and duration as strings rather than numbers. For production integrations, use 8-second requests. 1080p and 4k only support 8 seconds. For image-to-video, upload a local image file instead of a remote image URL.
Parameter limit: 1080p and 4k must be used with 8-second requests. Do not combine them with 4-second or 6-second requests. For 4K, also pass metadata.resolution="4k"; otherwise the downloaded file may be rendered as 1080p.
4K requests use the unified price. If you need to verify native 4K output, download the MP4 and inspect its media metadata. Do not rely only on create-task parameters for final file resolution.

Text-to-Video

Create a Task

curl -X POST "https://api.laozhang.ai/v1/videos" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F model="veo-3.1-fast-generate-preview" \
  -F prompt="A cinematic shot of a lighthouse at sunset, ocean waves hitting the rocks, stable slow camera push-in" \
  -F seconds="8" \
  -F duration="8" \
  -F size="1280x720" \
  -F resolution="720p" \
  -F aspectRatio="16:9" \
  -F 'metadata={"durationSeconds":8,"resolution":"720p","aspectRatio":"16:9"}' \
  -F negativePrompt="blurry, watermark, distorted, low quality" \
  -F seed="20260520"

Create Response

{
  "id": "task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "task_id": "task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "object": "video",
  "model": "veo-3.1-fast-generate-preview",
  "status": "queued",
  "progress": 0,
  "created_at": 1779283975
}

Image-to-Video

Image-to-video uses the same create endpoint. For a normal initial-image request, upload input_reference. input_reference represents a single initial image; for multi-reference images, use referenceImages.
curl -X POST "https://api.laozhang.ai/v1/videos" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F model="veo-3.1-generate-preview" \
  -F prompt="Animate the reference image with a gentle camera push-in, subtle background parallax, cinematic lighting" \
  -F seconds="8" \
  -F duration="8" \
  -F size="1280x720" \
  -F resolution="720p" \
  -F aspectRatio="16:9" \
  -F 'metadata={"durationSeconds":8,"resolution":"720p","aspectRatio":"16:9"}' \
  -F negativePrompt="blurry, watermark, deformed face, distorted body" \
  -F seed="20260520" \
  -F input_reference="@reference.jpg;type=image/jpeg"

4K Landscape Image-to-Video

For 4K landscape image-to-video, upload a 16:9 reference image and pass both resolution="4k" and metadata.resolution="4k".
curl -X POST "https://api.laozhang.ai/v1/videos" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F model="veo-3.1-fast-generate-preview" \
  -F prompt="Animate the 4K reference image with a slow cinematic camera push-in, subtle parallax, crisp details, stable lighting" \
  -F seconds="8" \
  -F duration="8" \
  -F size="3840x2160" \
  -F resolution="4k" \
  -F aspectRatio="16:9" \
  -F 'metadata={"durationSeconds":8,"resolution":"4k","aspectRatio":"16:9"}' \
  -F negativePrompt="blurry, watermark, distorted, low quality" \
  -F seed="20260521" \
  -F input_reference="@reference-4k.jpg;type=image/jpeg"

First/Last-Frame Generation

First/last-frame tasks must provide both a first frame and a final frame. Use input_reference for the first frame, and last_frame or lastFrame for the final frame. Use the Veo 3.1 series with 8-second requests. Do not pass negativePrompt for reference-image modes.
curl -X POST "https://api.laozhang.ai/v1/videos" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -F model="veo-3.1-generate-preview" \
  -F prompt="Smoothly transition from the first frame to the final frame, stable camera push-in, soft city bokeh, natural motion" \
  -F input_reference="@first-frame.png;type=image/png" \
  -F last_frame="@last-frame.png;type=image/png" \
  -F seconds="8" \
  -F size="1280x720" \
  -F resolution="720p" \
  -F aspectRatio="16:9" \
  -F seed="20260523"
Both last_frame and lastFrame are accepted for the final frame. Upstream reference-image modes do not support negativePrompt; do not pass it for first/last-frame or multi-reference requests.

Multi-Reference Images

Multi-reference image generation supports up to 3 images. For production integrations, repeat the referenceImages field and pass referenceType="asset". This mode only supports the Veo 3.1 series. Use 8-second requests and do not pass negativePrompt.
curl -X POST "https://api.laozhang.ai/v1/videos" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F model="veo-3.1-fast-generate-preview" \
  -F prompt="Use the product appearance and city lighting from the reference images to create a cinematic product shot" \
  -F seconds="8" \
  -F duration="8" \
  -F size="1280x720" \
  -F resolution="720p" \
  -F aspectRatio="16:9" \
  -F 'metadata={"durationSeconds":8,"resolution":"720p","aspectRatio":"16:9"}' \
  -F referenceType="asset" \
  -F seed="20260523" \
  -F referenceImages="@ref-1.png;type=image/png" \
  -F referenceImages="@ref-2.png;type=image/png"
Reference image dimensions should match the target size when possible. For example, use a 1280x720 image when size=1280x720. JPEG, PNG, and WebP are supported. Video extension is not supported yet; do not pass video.

Poll Status

Save the id or task_id from the create response, then poll status.
curl "https://api.laozhang.ai/v1/videos/task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Authorization: Bearer YOUR_API_KEY"
In progress:
{
  "id": "task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "object": "video",
  "model": "veo-3.1-fast-generate-preview",
  "status": "in_progress",
  "progress": 50,
  "created_at": 1779283975
}
Completed:
{
  "id": "task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "object": "video",
  "model": "veo-3.1-fast-generate-preview",
  "status": "completed",
  "progress": 100,
  "created_at": 1779283975,
  "completed_at": 1779284026
}

Status Values

StatusMeaning
queuedQueued
in_progressGenerating
completedCompleted and ready to download
failedFailed

Compatibility Status Polling

If existing code uses the older video generations polling path, use this compatibility endpoint:
curl "https://api.laozhang.ai/v1/video/generations/task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Authorization: Bearer YOUR_API_KEY"
This endpoint returns a task status object:
{
  "id": "task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "object": "video",
  "model": "veo-3.1-fast-generate-preview",
  "status": "completed",
  "progress": 100,
  "created_at": 1779283975,
  "completed_at": 1779284026
}
The compatibility polling endpoint does not return a separate public video URL. Download video results through /v1/videos/{id}/content.

Download Video

After the task completes, use /content to retrieve MP4 bytes. The API returns video file bytes, not a public video URL.
curl -L "https://api.laozhang.ai/v1/videos/task_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/content" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -o veo-3-1-output.mp4
The video file may lag briefly after GET /v1/videos/{id} returns completed. If the content endpoint returns task status is IN_PROGRESS, wait 10-20 seconds and retry.

Python Complete Example

import json
from pathlib import Path
import time

import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.laozhang.ai"

HEADERS = {
    "Authorization": f"Bearer {API_KEY}"
}


def video_metadata(seconds, resolution, aspect_ratio):
    return json.dumps({
        "durationSeconds": int(seconds),
        "resolution": resolution,
        "aspectRatio": aspect_ratio,
    })


def form_items(fields):
    return [(key, (None, value)) for key, value in fields.items()]


def create_text_video(
    prompt,
    model="veo-3.1-fast-generate-preview",
    seconds="8",
    size="1280x720",
    resolution="720p",
    aspect_ratio="16:9",
):
    fields = {
        "model": model,
        "prompt": prompt,
        "seconds": seconds,
        "duration": seconds,
        "size": size,
        "resolution": resolution,
        "aspectRatio": aspect_ratio,
        "metadata": video_metadata(seconds, resolution, aspect_ratio),
        "negativePrompt": "blurry, watermark, distorted, low quality",
    }
    response = requests.post(
        f"{BASE_URL}/v1/videos",
        headers=HEADERS,
        files={key: (None, value) for key, value in fields.items()},
        timeout=180,
    )
    response.raise_for_status()
    return response.json()


def create_image_video(
    prompt,
    image_path,
    model="veo-3.1-generate-preview",
    seconds="8",
    size="1280x720",
    resolution="720p",
    aspect_ratio="16:9",
):
    fields = {
        "model": model,
        "prompt": prompt,
        "seconds": seconds,
        "duration": seconds,
        "size": size,
        "resolution": resolution,
        "aspectRatio": aspect_ratio,
        "metadata": video_metadata(seconds, resolution, aspect_ratio),
        "negativePrompt": "blurry, watermark, distorted, low quality",
    }
    with open(image_path, "rb") as image_file:
        files = form_items(fields)
        files.append(("input_reference", (Path(image_path).name, image_file, "image/jpeg")))
        response = requests.post(
            f"{BASE_URL}/v1/videos",
            headers=HEADERS,
            files=files,
            timeout=180,
        )
    response.raise_for_status()
    return response.json()


def create_first_last_frame_video(
    prompt,
    first_frame_path,
    last_frame_path,
    model="veo-3.1-generate-preview",
):
    fields = {
        "model": model,
        "prompt": prompt,
        "seconds": "8",
        "size": "1280x720",
        "resolution": "720p",
        "aspectRatio": "16:9",
        "seed": "20260523",
    }
    with open(first_frame_path, "rb") as first_file, open(last_frame_path, "rb") as last_file:
        files = form_items(fields)
        files.append(("input_reference", (Path(first_frame_path).name, first_file, "image/png")))
        files.append(("last_frame", (Path(last_frame_path).name, last_file, "image/png")))
        response = requests.post(
            f"{BASE_URL}/v1/videos",
            headers=HEADERS,
            files=files,
            timeout=180,
        )
    response.raise_for_status()
    return response.json()


def create_reference_images_video(
    prompt,
    image_paths,
    model="veo-3.1-fast-generate-preview",
):
    fields = {
        "model": model,
        "prompt": prompt,
        "seconds": "8",
        "duration": "8",
        "size": "1280x720",
        "resolution": "720p",
        "aspectRatio": "16:9",
        "metadata": video_metadata("8", "720p", "16:9"),
        "referenceType": "asset",
    }
    open_files = []
    try:
        files = form_items(fields)
        for image_path in image_paths[:3]:
            image_file = open(image_path, "rb")
            open_files.append(image_file)
            files.append(("referenceImages", (Path(image_path).name, image_file, "image/png")))
        response = requests.post(
            f"{BASE_URL}/v1/videos",
            headers=HEADERS,
            files=files,
            timeout=180,
        )
    finally:
        for image_file in open_files:
            image_file.close()
    response.raise_for_status()
    return response.json()


def wait_for_video(task_id, timeout=900, interval=15):
    start = time.time()
    while time.time() - start < timeout:
        response = requests.get(
            f"{BASE_URL}/v1/videos/{task_id}",
            headers=HEADERS,
            timeout=60,
        )
        response.raise_for_status()
        payload = response.json()

        status = payload.get("status")
        progress = payload.get("progress", 0)
        print(f"status={status}, progress={progress}")

        if status == "completed":
            return payload
        if status == "failed":
            raise RuntimeError(f"video generation failed: {payload}")

        time.sleep(interval)

    raise TimeoutError("video generation timed out")


def download_video(task_id, output_path, retries=8, interval=10):
    last_error = None
    for _ in range(retries):
        response = requests.get(
            f"{BASE_URL}/v1/videos/{task_id}/content",
            headers=HEADERS,
            timeout=180,
        )
        if response.status_code == 200:
            with open(output_path, "wb") as output_file:
                output_file.write(response.content)
            return output_path

        last_error = response.text
        if "IN_PROGRESS" not in response.text and "in_progress" not in response.text:
            response.raise_for_status()
        time.sleep(interval)

    raise RuntimeError(f"download failed: {last_error}")


if __name__ == "__main__":
    task = create_text_video(
        prompt="A cinematic lighthouse at sunset, ocean waves, slow camera push-in",
        model="veo-3.1-fast-generate-preview",
        seconds="8",
        size="1280x720",
    )
    task_id = task.get("id") or task.get("task_id")
    wait_for_video(task_id)
    download_video(task_id, "veo-output.mp4")

FAQ

/v1/videos/{id}/content returns video/mp4 bytes, not a public video URL. /v1/video/generations/{id} returns a task status object, not a separate public video URL. In production, download it server-side, store it in your own OSS/CDN, and return your own URL to users.
Use the default group for Veo 3.1 official forwarding. Create a dedicated token and set Billing mode to Pay-per-request for cleaner billing review.
Billing uses Pay-per-request, not separate duration or resolution pricing. veo-3.1-fast-generate-preview is $0.3/call, and veo-3.1-generate-preview is $1.2/call. For production integrations, use 8-second requests; 1080p and 4k require 8 seconds. For 4K, also pass metadata.resolution="4k".
Yes. Use input_reference for a single initial image, input_reference + last_frame for first/last-frame generation, and up to 3 repeated referenceImages fields with referenceType="asset" for multi-reference generation. Video extension is not supported yet; do not pass video.
Do not pass generateAudio. Veo 3 / Veo 3.1 models have native audio, but this API does not support toggling audio with generateAudio; describe the desired audio in the prompt instead.
Not recommended. Veo 3.1 official forwarding should use the same /v1/videos task API style as Sora2 official forwarding.