Documentation Index
Fetch the complete documentation index at: https://docs.venice.ai/llms.txt
Use this file to discover all available pages before exploring further.
Video generation is async. Submit a job, save queue_id, then poll /video/retrieve until the response is video/mp4.
Endpoints
| Endpoint | Purpose | Required |
|---|
POST /video/quote | Get price in USD before generating | No |
POST /video/queue | Submit generation request | Yes |
POST /video/retrieve | Poll status or download video | Yes |
POST /video/complete | Delete video from storage | No |
Step 1: Queue Generation
Request:
POST https://api.venice.ai/api/v1/video/queue
Authorization: Bearer $VENICE_API_KEY
Content-Type: application/json
{
"model": "wan-2.5-preview-text-to-video",
"prompt": "A gondola gliding through Venice canals at sunset",
"duration": "5s",
"resolution": "720p",
"aspect_ratio": "16:9"
}
Response (200):
{
"model": "wan-2.5-preview-text-to-video",
"queue_id": "123e4567-e89b-12d3-a456-426614174000"
}
For Grok Imagine Private models, the queue response includes an extra download_url field:
{
"model": "grok-imagine-text-to-video-private",
"queue_id": "123e4567-e89b-12d3-a456-426614174000",
"download_url": "https://private-share.venice.ai/v1/share/read/..."
}
download_url is a pre-signed URL you use to download the finished video instead of reading it from the retrieve response. It is only returned once in the queue response, so persist it alongside queue_id. This applies to all four Grok Imagine Private variants:
grok-imagine-text-to-video-private
grok-imagine-image-to-video-private
grok-imagine-reference-to-video-private
grok-imagine-video-to-video-private
Unlike the public grok-imagine-*-video variants, Grok Imagine Private models are not billed for content-moderation rejections, so you only pay for successful generations.
Save model, queue_id, and download_url (if present) for all subsequent calls.
Private download links
For private models, download_url is how you fetch the finished file once the job is complete. The link is short-lived and single-purpose: it is there to deliver the MP4 to you, not to serve as a long-term or widely shared URL.
If a download is interrupted, you can retry the same GET a few times from the same environment until the file finishes. Those retries are for recovering from network blips—not for polling the same link indefinitely, sharing it across many clients, or embedding it like a permanent media URL. Patterns like that often show up as 429 or 410, which can be surprising if you expected the link to behave like regular file hosting.
For reliability, GET requests should originate from one client network. There is some flexibility if your IP changes once (for example you disconnect a VPN and try again), but wide variation in source IPs usually will not work.
The URL stays valid for up to 24 hours, or until the object is removed.
If you need a stable URL, public playback, or repeated access over time, save the file to your own storage first and serve it from there.
Privacy: revoke the link with DELETE
When you are done fetching the file—or if you decide not to keep it—you can call DELETE on the same download_url. No Venice API key is required on that request. This is optional but recommended when privacy matters, because some proxies and middleboxes outside Venice keep logs of full URLs, and deleting the link is the simplest way to narrow the window where the pre-signed URL exists.
curl -X DELETE "$DOWNLOAD_URL"
Flow: poll /video/retrieve until COMPLETED → GET the download_url (retry lightly if the transfer drops) → save the file where you need it → DELETE the download_url if you want the link invalidated → optionally call /video/complete if you still use queue-based cleanup.
Step 2: Poll for Completion
Request:
POST https://api.venice.ai/api/v1/video/retrieve
Authorization: Bearer $VENICE_API_KEY
Content-Type: application/json
{
"model": "wan-2.5-preview-text-to-video",
"queue_id": "123e4567-e89b-12d3-a456-426614174000"
}
Response depends on status:
| Content-Type | Meaning | Action |
|---|
application/json | Still processing | Wait 5s, poll again |
video/mp4 | Complete | Response body is the video file |
application/json with "COMPLETED" | Complete, video not inline | GET the download_url from the queue response |
Processing response (200, application/json):
{
"status": "PROCESSING",
"average_execution_time": 145000,
"execution_duration": 53200
}
Times are in milliseconds. Use average_execution_time to estimate remaining wait.
Complete response (200, video/mp4):
Response body is raw binary video data. Save to file.
Complete response (200, application/json with "COMPLETED"):
For models that returned a download_url at queue time, retrieve always returns JSON. Fetch the video with GET download_url (no auth header). See Private download links for how these URLs work, retries, and optional DELETE.
Step 3: Cleanup (Optional)
Either auto-delete on retrieval:
{
"model": "wan-2.5-preview-text-to-video",
"queue_id": "123e4567-e89b-12d3-a456-426614174000",
"delete_media_on_completion": true
}
Or call /video/complete after saving:
POST https://api.venice.ai/api/v1/video/complete
Authorization: Bearer $VENICE_API_KEY
Content-Type: application/json
{
"model": "wan-2.5-preview-text-to-video",
"queue_id": "123e4567-e89b-12d3-a456-426614174000"
}
Response (200):
Complete Example
import os
import time
import requests
API_KEY = os.environ.get("VENICE_API_KEY")
BASE_URL = "https://api.venice.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
# Queue
resp = requests.post(f"{BASE_URL}/video/queue", headers=HEADERS, json={
"model": "wan-2.5-preview-text-to-video",
"prompt": "A gondola gliding through Venice canals at sunset",
"duration": "5s",
"resolution": "720p",
"aspect_ratio": "16:9"
})
data = resp.json()
model, queue_id = data["model"], data["queue_id"]
download_url = data.get("download_url")
# Poll
while True:
resp = requests.post(f"{BASE_URL}/video/retrieve", headers=HEADERS,
json={"model": model, "queue_id": queue_id})
if "video/mp4" in resp.headers.get("Content-Type", ""):
with open("output.mp4", "wb") as f:
f.write(resp.content)
break
if resp.json().get("status") == "COMPLETED" and download_url:
with open("output.mp4", "wb") as f:
f.write(requests.get(download_url).content)
break
time.sleep(5)
# Cleanup
requests.post(f"{BASE_URL}/video/complete", headers=HEADERS,
json={"model": model, "queue_id": queue_id})
Request Parameters
Queue Request
| Parameter | Type | Required | Default | Description |
|---|
model | string | Yes | - | Model ID. Use wan-2.5-preview-text-to-video for text-to-video, wan-2.5-preview-image-to-video for image-to-video |
prompt | string | Yes | - | What to generate. Max 2500 chars |
negative_prompt | string | No | "low resolution, error, worst quality, low quality, defects" | What to avoid |
duration | string | Yes | - | "5s" or "10s" |
resolution | string | No | "720p" | "480p", "720p", or "1080p" |
aspect_ratio | string | Conditional | - | Model-dependent. Required for models that expose aspect-ratio options; omit for models that do not support aspect-ratio selection |
audio | boolean | Conditional | true (when supported) | Only valid for models with supportsAudioConfig: true; omit for models without audio config support |
image_url | string | Only for image-to-video | - | URL or base64 data URL of source image |
audio_url | string | Conditional | - | URL or base64 data URL of reference audio for models that support audio input |
Queue validation is model-specific. Check /models?type=video for each model’s supported request fields before calling /video/queue.
Quote Request
| Parameter | Type | Required | Default | Description |
|---|
model | string | Yes | - | Model ID to price |
duration | string | Yes | - | "5s" or "10s" |
resolution | string | No | "720p" | "480p", "720p", or "1080p" |
aspect_ratio | string | Conditional | - | Include when the selected model supports or requires aspect-ratio selection |
audio | boolean | Conditional | true (when supported) | Only valid for models with supportsAudioConfig: true |
Retrieve Request
| Parameter | Type | Required | Default | Description |
|---|
model | string | Yes | - | From queue response |
queue_id | string | Yes | - | From queue response |
delete_media_on_completion | boolean | No | false | Delete video after successful retrieval |
Complete Request
| Parameter | Type | Required | Description |
|---|
model | string | Yes | From queue response |
queue_id | string | Yes | From queue response |
Image to Video
For image-to-video models, pass source image via image_url. The prompt describes desired motion, not the image content.
{
"model": "wan-2.5-preview-image-to-video",
"prompt": "Camera slowly zooms in as leaves rustle in the wind",
"image_url": "https://example.com/image.jpg",
"duration": "5s"
}
Or with base64:
{
"model": "wan-2.5-preview-image-to-video",
"prompt": "Camera slowly zooms in as leaves rustle in the wind",
"image_url": "data:image/jpeg;base64,/9j/4AAQ...",
"duration": "5s"
}
Price Quote
Get exact cost before generating. Send only pricing inputs (model, duration, and optional resolution, aspect_ratio, audio):
Request:
{
"model": "wan-2.5-preview-text-to-video",
"duration": "10s",
"resolution": "1080p"
}
Response:
Quote is in USD.
Errors
| Status | Returned By | Meaning | Action |
|---|
| 400 | queue, quote, retrieve, complete | Invalid parameters | Check request body against schema |
| 401 | queue, retrieve, complete | Auth failed | Check API key |
| 402 | queue | Insufficient balance | Add funds |
| 404 | retrieve, download_url | Media not found (invalid, expired, or deleted) | Verify model/queue_id or re-queue |
| 410 | download_url | Pre-signed URL expired, fully used, or revoked (for example after DELETE) | Start a new generation if you need another file; each link is intentionally short-lived |
| 429 | download_url | Rate limited—often from many retries or repeated fetches of the same link | Finish the download (a few retries are fine if the connection drops), save a local copy, and use DELETE if you want to clear the link; keep ongoing access on your own storage |
| 413 | queue | Payload too large | Reduce image/audio size |
| 422 | queue, retrieve | Content violation | Modify prompt |
| 500 | queue, retrieve, complete | Inference/processing failed | Retry with backoff; contact support if persistent |
| 503 | retrieve | Model at capacity | Retry with backoff |
Polling Strategy
- Poll
/video/retrieve on an interval (for example, every 5 seconds)
- If
Content-Type is application/json and status is "PROCESSING", wait and poll again. Use average_execution_time and execution_duration (milliseconds) to estimate remaining time
- If
Content-Type is video/mp4, save the response body as your output file
- If
Content-Type is application/json and status is "COMPLETED", GET the download_url from the queue response to fetch the video (see Private download links)
- If you used
download_url, consider DELETE on that URL when you are done to narrow how long the pre-signed URL exists; then optionally set delete_media_on_completion: true on retrieve or call /video/complete for queue-based cleanup
- Handle
404 as invalid, expired, or deleted media; handle 500/503 with retries/backoff
Available Models
See Video Models for current model list and pricing.