Skip to main content

Gemini Video Generation (Veo)

LiteLLM supports Google's Veo video generation models through a unified API interface.

PropertyDetails
DescriptionGoogle's Veo AI video generation models
Provider Route on LiteLLMgemini/
Supported Modelsveo-3.0-generate-preview, veo-3.1-generate-preview
Cost Trackingโœ… Duration-based pricing
Logging Supportโœ… Full request/response logging
Proxy Server Supportโœ… Full proxy integration with virtual keys
Spend Managementโœ… Budget tracking and rate limiting
Link to Provider DocGoogle Veo Documentation โ†—

Quick Startโ€‹

Required API Keysโ€‹

import os 
os.environ["GEMINI_API_KEY"] = "your-google-api-key"
# OR
os.environ["GOOGLE_API_KEY"] = "your-google-api-key"

Basic Usageโ€‹

from litellm import video_generation, video_status, video_content
import os
import time

os.environ["GEMINI_API_KEY"] = "your-google-api-key"

# Step 1: Generate video
response = video_generation(
model="gemini/veo-3.0-generate-preview",
prompt="A cat playing with a ball of yarn in a sunny garden"
)

print(f"Video ID: {response.id}")
print(f"Initial Status: {response.status}") # "processing"

# Step 2: Poll for completion
while True:
status_response = video_status(
video_id=response.id
)

print(f"Current Status: {status_response.status}")

if status_response.status == "completed":
break
elif status_response.status == "failed":
print("Video generation failed")
break

time.sleep(10) # Wait 10 seconds before checking again

# Step 3: Download video content
video_bytes = video_content(
video_id=response.id
)

# Save to file
with open("generated_video.mp4", "wb") as f:
f.write(video_bytes)

print("Video downloaded successfully!")

Supported Modelsโ€‹

Model NameDescriptionMax DurationStatus
veo-3.0-generate-previewVeo 3.0 video generation8 secondsPreview
veo-3.1-generate-previewVeo 3.1 video generation8 secondsPreview

Video Generation Parametersโ€‹

LiteLLM automatically maps OpenAI-style parameters to Veo's format:

OpenAI ParameterVeo ParameterDescriptionExample
promptpromptText description of the video"A cat playing"
sizeaspectRatioVideo dimensions โ†’ aspect ratio"1280x720" โ†’ "16:9"
secondsdurationSecondsDuration in seconds"8" โ†’ 8
input_referenceimageReference image to animateFile object or path
modelmodelModel to use"gemini/veo-3.0-generate-preview"

Size to Aspect Ratio Mappingโ€‹

LiteLLM automatically converts size dimensions to Veo's aspect ratio format:

  • "1280x720", "1920x1080" โ†’ "16:9" (landscape)
  • "720x1280", "1080x1920" โ†’ "9:16" (portrait)

Supported Veo Parametersโ€‹

Based on Veo's API:

  • prompt (required): Text description with optional audio cues
  • aspectRatio: "16:9" (default) or "9:16"
  • resolution: "720p" (default) or "1080p" (Veo 3.1 only, 16:9 aspect ratio only)
  • durationSeconds: Video length (max 8 seconds for most models)
  • image: Reference image for animation
  • negativePrompt: What to exclude from the video (Veo 3.1)
  • referenceImages: Style and content references (Veo 3.1 only)

Complete Workflow Exampleโ€‹

import litellm
import time

def generate_and_download_veo_video(
prompt: str,
output_file: str = "video.mp4",
size: str = "1280x720",
seconds: str = "8"
):
"""
Complete workflow for Veo video generation.

Args:
prompt: Text description of the video
output_file: Where to save the video
size: Video dimensions (e.g., "1280x720" for 16:9)
seconds: Duration in seconds

Returns:
bool: True if successful
"""
print(f"๐ŸŽฌ Generating video: {prompt}")

# Step 1: Initiate generation
response = litellm.video_generation(
model="gemini/veo-3.0-generate-preview",
prompt=prompt,
size=size, # Maps to aspectRatio
seconds=seconds # Maps to durationSeconds
)

video_id = response.id
print(f"โœ“ Video generation started (ID: {video_id})")

# Step 2: Wait for completion
max_wait_time = 600 # 10 minutes
start_time = time.time()

while time.time() - start_time < max_wait_time:
status_response = litellm.video_status(video_id=video_id)

if status_response.status == "completed":
print("โœ“ Video generation completed!")
break
elif status_response.status == "failed":
print("โœ— Video generation failed")
return False

print(f"โณ Status: {status_response.status}")
time.sleep(10)
else:
print("โœ— Timeout waiting for video generation")
return False

# Step 3: Download video
print("โฌ‡๏ธ Downloading video...")
video_bytes = litellm.video_content(video_id=video_id)

with open(output_file, "wb") as f:
f.write(video_bytes)

print(f"โœ“ Video saved to {output_file}")
return True

# Use it
generate_and_download_veo_video(
prompt="A serene lake at sunset with mountains in the background",
output_file="sunset_lake.mp4"
)

Async Usageโ€‹

from litellm import avideo_generation, avideo_status, avideo_content
import asyncio

async def async_video_workflow():
# Generate video
response = await avideo_generation(
model="gemini/veo-3.0-generate-preview",
prompt="A cat playing with a ball of yarn"
)

# Poll for completion
while True:
status = await avideo_status(video_id=response.id)
if status.status == "completed":
break
await asyncio.sleep(10)

# Download content
video_bytes = await avideo_content(video_id=response.id)

with open("video.mp4", "wb") as f:
f.write(video_bytes)

# Run it
asyncio.run(async_video_workflow())

LiteLLM Proxy Usageโ€‹

Configurationโ€‹

Add Veo models to your config.yaml:

model_list:
- model_name: veo-3
litellm_params:
model: gemini/veo-3.0-generate-preview
api_key: os.environ/GEMINI_API_KEY

Start the proxy:

litellm --config config.yaml
# Server running on http://0.0.0.0:4000

Making Requestsโ€‹

# Step 1: Generate video
curl --location 'http://0.0.0.0:4000/videos/generations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer sk-1234' \
--data '{
"model": "veo-3",
"prompt": "A cat playing with a ball of yarn in a sunny garden"
}'

# Response: {"id": "gemini::operations/generate_12345::...", "status": "processing", ...}

# Step 2: Check status
curl --location 'http://0.0.0.0:4000/videos/status' \
--header 'Authorization: Bearer sk-1234' \
--data '{
"video_id": "gemini::operations/generate_12345::..."
}'

# Step 3: Download video (when status is "completed")
curl --location 'http://0.0.0.0:4000/videos/retrieval' \
--header 'Authorization: Bearer sk-1234' \
--data '{
"video_id": "gemini::operations/generate_12345::..."
}' \
--output video.mp4

Cost Trackingโ€‹

LiteLLM automatically tracks costs for Veo video generation:

response = litellm.video_generation(
model="gemini/veo-3.0-generate-preview",
prompt="A beautiful sunset"
)

# Cost is calculated based on video duration
# Veo pricing: ~$0.10 per second (estimated)
# Default video duration: ~5 seconds
# Estimated cost: ~$0.50

Differences from OpenAI Video APIโ€‹

FeatureOpenAI (Sora)Gemini (Veo)
Reference Imagesโœ… SupportedโŒ Not supported
Size Controlโœ… SupportedโŒ Not supported
Duration Controlโœ… SupportedโŒ Not supported
Video Remix/Editโœ… SupportedโŒ Not supported
Video Listโœ… SupportedโŒ Not supported
Prompt-based Generationโœ… Supportedโœ… Supported
Async Operationsโœ… Supportedโœ… Supported

Error Handlingโ€‹

from litellm import video_generation, video_status, video_content
from litellm.exceptions import APIError, Timeout

try:
response = video_generation(
model="gemini/veo-3.0-generate-preview",
prompt="A beautiful landscape"
)

# Poll with timeout
max_attempts = 60 # 10 minutes (60 * 10s)
for attempt in range(max_attempts):
status = video_status(video_id=response.id)

if status.status == "completed":
video_bytes = video_content(video_id=response.id)
with open("video.mp4", "wb") as f:
f.write(video_bytes)
break
elif status.status == "failed":
raise APIError("Video generation failed")

time.sleep(10)
else:
raise Timeout("Video generation timed out")

except APIError as e:
print(f"API Error: {e}")
except Timeout as e:
print(f"Timeout: {e}")
except Exception as e:
print(f"Unexpected error: {e}")

Best Practicesโ€‹

  1. Always poll for completion: Veo video generation is asynchronous and can take several minutes
  2. Set reasonable timeouts: Allow at least 5-10 minutes for video generation
  3. Handle failures gracefully: Check for failed status and implement retry logic
  4. Use descriptive prompts: More detailed prompts generally produce better results
  5. Store video IDs: Save the operation ID/video ID to resume polling if your application restarts

Troubleshootingโ€‹

Video generation times outโ€‹

# Increase polling timeout
max_wait_time = 900 # 15 minutes instead of 10

Video not found when downloadingโ€‹

# Make sure video is completed before downloading
status = video_status(video_id=video_id)
if status.status != "completed":
print("Video not ready yet!")

API key errorsโ€‹

# Verify your API key is set
import os
print(os.environ.get("GEMINI_API_KEY"))

# Or pass it explicitly
response = video_generation(
model="gemini/veo-3.0-generate-preview",
prompt="...",
api_key="your-api-key-here"
)

See Alsoโ€‹