EasyRouterEasyRouter
User GuideAPI DocsConnect Agent Tools
AI Model APIVideos

Veo 3.1 Video Generation

Use EasyRouter's unified API to call Google Veo 3.1 video generation models — text-to-video and image-to-video, with optional synchronized audio generation.

Veo 3.1 is Google's latest-generation video creation model, supporting text and image inputs, up to 4K resolution output, and native synchronized speech and sound effect generation. EasyRouter exposes it through the unified /v1/video/generations async task endpoint.

Veo 3.1 uses an async task-based API: submit a request, receive a task_id, poll for status, then download the video from data.url.


1. Supported Models

Model IDVersionStrengthsBest For
veo-3.1-generate-001Veo 3.1Highest quality, 4K support, native audioHigh-quality creative content, commercial production
veo-3.1-fast-generate-001Veo 3.1 FastFaster speed, balanced qualityRapid iteration, batch generation
veo-3.1-lite-generate-001Veo 3.1 LiteFastest speed, lowest costPrototyping, high-volume testing

All 3 models share the same endpoint, differentiated only by the model field. All support text-to-video, image-to-video, and optional audio generation.


2. Common Endpoints

2.1 Submit Task

POST /v1/video/generations

Request Headers

HeaderRequiredDescription
AuthorizationBearer sk-YourApiKey
Content-Typeapplication/json

Request Body Fields

FieldTypeRequiredDescription
modelstringVeo 3.1 model ID (see table above)
promptstringVideo description; English recommended for best results
sizestringResolution: 720p / 1080p / 4000 (4K, standard model only). Default: 1080p
resolutionstringSame as size (recommended; aligns with upstream. When both are present, this field wins)
durationintVideo duration in seconds: 4 / 6 / 8. Default: 8
secondsstringString form of duration (OpenAI Sora compatibility)
aspect_ratiostringAspect ratio: 16:9 / 9:16. Default: 16:9
generate_audioboolGenerate synchronized audio (speech, sound effects, ambient sound). Default: true (it is highly recommended to set this to false to save cost when you don't need audio)
negative_promptstringNegative prompt describing content to exclude
seedintRandom seed (place inside metadata.seed, see below)
imagestringImage-to-video first-frame image. Accepts HTTP(S) URL / data URI / raw base64 (see Image Input Formats)
imagesstring[]First-frame array; only images[0] is used. image takes precedence when both are provided
last_frame_imagestringLast-frame image (combine with image / images[0] for first+last-frame interpolation, Veo 3.1 only). Same formats as image
reference_imagesstring[]Asset reference images (up to 3); forwarded as referenceType: "asset" upstream. Mutually exclusive with image / last_frame_image, only supported for duration=8
metadataobjectContainer for Veo-native parameters, see Section 3 below

OpenAI-style top-level fields are auto-mapped: snake_case top-level fields like generate_audio / negative_prompt / aspect_ratio are automatically forwarded as the corresponding camelCase parameters to upstream Veo. You can also place them inside metadata (snake_case or camelCase both work) — equivalent behavior.

generate_audio: true roughly doubles the cost. The billing default is true, so if audio is not needed, explicitly set generate_audio: false to avoid being charged at the audio-included rate. See Section 7 for pricing details.

Response

{
  "id": "task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j",
  "task_id": "task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j",
  "object": "video",
  "model": "veo-3.1-generate-001",
  "status": "queued",
  "progress": 0,
  "created_at": 1778590105
}

2.2 Query Task Status

GET /v1/video/generations/{task_id}

The response uses EasyRouter's unified {code, message, data} wrapper format.

Response (Completed / succeeded)

{
  "code": "success",
  "message": "",
  "data": {
    "task_id": "task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j",
    "status": "succeeded",
    "error": null,
    "format": "mp4",
    "metadata": null,
    "url": "https://easyrouter.io/v1/videos/task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j/content"
  }
}

Response (Failed / failed)

{
  "code": "success",
  "message": "",
  "data": {
    "task_id": "task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j",
    "status": "failed",
    "error": "SafetyFilterActivated: prompt violates content policy",
    "format": null,
    "metadata": null,
    "url": null
  }
}

Status Enum

StatusDescription
queuedSubmitted, waiting to start
processingGenerating
succeededCompleted; data.url contains the video download URL
failedFailed; data.error contains details

data Fields

FieldTypeDescription
task_idstringTask ID
statusstringTask status
errorstring / nullFailure reason; null on success
formatstring / nullOutput format (e.g., mp4); null while processing or on failure
metadataobject / nullAdditional metadata
urlstring / nullVideo download URL; null while processing or on failure

The video download URL (data.url) is a temporary signed link, valid for 24 hours. Download or transfer to your own storage immediately.

2.3 Image Input Formats

Both image and images[0] accept the following three formats. EasyRouter automatically detects and converts them into inline base64 (the format Veo's upstream API requires):

FormatExampleNotes
HTTP(S) URLhttps://example.com/foo.pngEasyRouter downloads the image server-side, base64-encodes it, and forwards. URL must be publicly reachable and not expired
data URIdata:image/png;base64,iVBOR...Inline data passed through directly, no network fetch required. Useful when you don't want to expose the image URL
raw base64iVBORw0KGgo... (no prefix)Plain base64 string; MIME type is auto-sniffed

Limits:

  • Max decoded image size: 20 MB
  • Download timeout for URL form: 30 seconds
  • Parse failure (URL unreachable / oversize / invalid base64) returns 400 parse images[0] failed: ... synchronously, no quota consumed

gs:// GCS native URIs are not supported. Use https://storage.googleapis.com/... HTTPS form instead.


3. metadata Advanced Parameters

metadata is the container for Veo-native parameters that don't have OpenAI-style equivalents. All top-level fields can also be placed inside metadata (snake_case or camelCase) to override defaults.

FieldTypeDescription
seedintRandom seed (recommended placement)
personGeneration / person_generationstringPerson generation policy: allow_all / allow_adult / dont_allow
storageUri / storage_uristringWrite the result directly to a GCS bucket path (vertex channel only, requires permissions)
compressionQuality / compression_qualitystringCompression quality: optimized (default) / lossless
resizeMode / resize_modestringImage-to-video resize policy: crop / fit
sampleCount / sample_countintNumber of videos per request, currently fixed at 1, your value is overridden

Precedence: camelCase in metadata > snake_case in metadata > top-level fields. In other words, when there's a name collision, metadata camelCase wins.


4. OpenAI-Compatible Endpoints (Optional)

In addition to /v1/video/generations, Veo 3.1 also supports OpenAI-style /v1/videos endpoints. Both are fully equivalent.

Submit: POST /v1/videos (identical request body fields)

Query: GET /v1/videos/{task_id} returns OpenAI flat format:

{
  "id": "task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j",
  "object": "video",
  "model": "veo-3.1-generate-001",
  "status": "completed",
  "progress": 100,
  "created_at": 1778590105,
  "completed_at": 1778590201
}

The OpenAI-compatible query endpoint does not return the video URL. Use /v1/video/generations/{task_id} and get the download URL from data.url.


5. Full Request Examples

# Step 1: Submit task
curl -X POST https://easyrouter.io/v1/video/generations \
  -H "Authorization: Bearer sk-YourApiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1-generate-001",
    "prompt": "A golden retriever playing fetch on a sunny beach, cinematic wide shot, slow motion",
    "size": "1080p",
    "duration": 8,
    "aspect_ratio": "16:9"
  }'

# Step 2: Poll (recommended interval: 10~15 seconds)
curl https://easyrouter.io/v1/video/generations/task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j \
  -H "Authorization: Bearer sk-YourApiKey"

# Step 3: When data.status == "succeeded", download from data.url
curl -o output.mp4 "https://easyrouter.io/v1/videos/task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j/content"
# Enable generate_audio: true for synchronized speech, sound effects, and ambient sound
curl -X POST https://easyrouter.io/v1/video/generations \
  -H "Authorization: Bearer sk-YourApiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1-generate-001",
    "prompt": "A jazz musician performing on a rainy street at night, neon lights reflecting on wet pavement",
    "size": "1080p",
    "duration": 8,
    "generate_audio": true
  }'

Enabling audio roughly doubles the cost. Veo 3.1 standard, 1080p, 8s with audio = 1,360,000 quota.

# Pass a reference image via images
# The model generates motion starting from this image
curl -X POST https://easyrouter.io/v1/video/generations \
  -H "Authorization: Bearer sk-YourApiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1-generate-001",
    "prompt": "The cat slowly opens its eyes and stretches, sunlight streaming through the window",
    "images": ["https://example.com/cat.jpg"],
    "size": "1080p",
    "duration": 8,
    "aspect_ratio": "16:9"
  }'
# 9:16 portrait i2v + synchronized audio — common e-commerce short-form video case
curl -X POST https://easyrouter.io/v1/video/generations \
  -H "Authorization: Bearer sk-YourApiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1-fast-generate-001",
    "prompt": "Reference image constraint: use images[0] as the exact first frame. Preserve subject, color, logo and composition. Animate natural product motion only.",
    "images": ["https://your-bucket.example.com/product.png"],
    "size": "1080p",
    "duration": 6,
    "aspect_ratio": "9:16",
    "generate_audio": true
  }'
  • Image URL must be publicly reachable and not expired. For private buckets, use a pre-signed URL — otherwise you'll get 400 parse images[0] failed: download image returned http 403.
  • aspect_ratio: "9:16" must be set explicitly; otherwise the video defaults to 16:9 landscape regardless of size.
# Veo 3.1 only: pass first + last frame, the model interpolates the transition
curl -X POST https://easyrouter.io/v1/video/generations \
  -H "Authorization: Bearer sk-YourApiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1-generate-001",
    "prompt": "Smooth cinematic transition between a serene garden and a bustling city.",
    "image": "https://example.com/start.jpg",
    "last_frame_image": "https://example.com/end.jpg",
    "size": "1080p",
    "duration": 8,
    "aspect_ratio": "16:9"
  }'
  • Supported only on Veo 3.1 series (generate-001 / fast / lite).
  • Both images are downloaded and base64-encoded server-side; URLs must be publicly reachable.
# referenceImages: use multiple reference images to keep subject/scene consistent
# (mutually exclusive with image / last_frame_image)
curl -X POST https://easyrouter.io/v1/video/generations \
  -H "Authorization: Bearer sk-YourApiKey" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1-generate-001",
    "prompt": "The same character walks through a futuristic neon-lit city at night, cinematic.",
    "reference_images": [
      "https://example.com/character-front.png",
      "https://example.com/character-side.png",
      "https://example.com/scene-style.png"
    ],
    "size": "1080p",
    "duration": 8,
    "aspect_ratio": "16:9"
  }'
  • Mutual exclusion: reference_images cannot be used together with image / images / last_frame_image. Mixing them returns 400 reference_images is mutually exclusive ....
  • Up to 3 entries; more returns 400 reference_images supports at most 3 entries.
  • Only duration=8 is supported; other durations are rejected upstream.
  • Forwarded as referenceType="asset". Veo 3.1 does not support the style reference type.

6. Model Comparison

Veo 3.1Veo 3.1 FastVeo 3.1 Lite
Model IDveo-3.1-generate-001veo-3.1-fast-generate-001veo-3.1-lite-generate-001
QualityHighestBalancedBasic
Speed (8s video, measured)~90–130s~75–105s~50–80s
Max Resolution4K1080p1080p
Audio
Image-to-Video

7. Billing

Video Only (generate_audio: false)

Model720p1080p4K
veo-3.1-generate-001$0.20 / sec$0.20 / sec$0.40 / sec
veo-3.1-fast-generate-001$0.08 / sec$0.10 / sec$0.25 / sec
veo-3.1-lite-generate-001$0.03 / sec$0.05 / sec

Video + Audio (generate_audio: true)

Model720p1080p4K
veo-3.1-generate-001$0.40 / sec$0.40 / sec$0.60 / sec
veo-3.1-fast-generate-001$0.10 / sec$0.12 / sec$0.30 / sec
veo-3.1-lite-generate-001$0.05 / sec$0.08 / sec

Quota calculation formula:

quota = modelPrice × QuotaPerUnit × groupRatio × pricingRatio × seconds

QuotaPerUnit = 500,000
groupRatio   = 1.0 (production default group)

Example (veo-3.1-generate-001, 1080p, 8s, with audio):
  modelPrice   = 0.20
  pricingRatio = 2.0 (audio doubles the cost)
  quota = 0.20 × 500,000 × 1 × 2.0 × 8 = 1,600,000

Example (veo-3.1-lite-generate-001, 1080p, 8s, video only):
  modelPrice   = 0.03
  pricingRatio ≈ 1.667 (1080p multiplier)
  quota = 0.03 × 500,000 × 1 × 1.667 × 8 ≈ 200,000

On task failure (failed), EasyRouter automatically refunds quota to your account. No manual action required.


8. Polling Guide

ItemRecommendation
Poll intervalEvery 10–15 seconds; minimum 5 seconds
Terminal statedata.status == "succeeded" or data.status == "failed"
Total timeout5 minutes recommended
Typical duration (8s video, measured)Lite: 50–80s; Fast: 75–105s; Standard: 90–130s
Video URL validity24 hours; download or transfer immediately

Simple Polling Script (Bash)

#!/bin/bash
TID="task_DduhCcHShyasO6lCV7o5SK9JQEYUnO1j"
KEY="sk-YourApiKey"
while true; do
  RESP=$(curl -sS "https://easyrouter.io/v1/video/generations/$TID" \
    -H "Authorization: Bearer $KEY")
  echo "$RESP"
  STATUS=$(echo "$RESP" | python3 -c \
    "import sys,json;print(json.load(sys.stdin)['data'].get('status',''))")
  case "$STATUS" in
    succeeded|failed) break ;;
  esac
  sleep 15
done

9. Error Handling

HTTP Errors

CodeCauseAction
400Invalid parameters (missing prompt, unsupported duration, or image parsing failure: parse images[0] failed: ...)Check request body; see FAQ for image-related errors
401API Key invalid or expiredCheck Authorization header
403API Key lacks access to this modelCheck token model allowlist
402Insufficient balanceRecharge at EasyRouter console

Task Failure (failed)

Common ReasonRecommendation
Safety policy violation (data.error contains safety review details)Revise prompt; avoid sensitive content; use negative_prompt
Inaccessible image URLEnsure images URLs are publicly accessible and not expired
Unsupported duration valueUse 4, 6, or 8 only
4K not supported by modelOnly veo-3.1-generate-001 supports size: "4000"

10. FAQ