Skip to main content
POST /v3/videos is a deterministic, provider-agnostic video endpoint. You pass a model and a prompt; Opper runs the job and gives you a URL to poll. The same two-step flow works across every video provider (OpenAI Sora, xAI Grok-Imagine, Pruna Wan, Google Veo) — only the contents of parameters differ per model.
Video generation is asynchronous: submitting returns immediately with an id, and you poll for the result. A clip typically takes from ~30 seconds to a few minutes depending on the model, resolution, and duration.

How it works

  1. SubmitPOST /v3/videos with model + prompt202 { id, status_url }
  2. PollGET {status_url} until status is completed or failed
  3. Download — fetch the presigned url from the completed response (valid 1 hour)

Run your first generation

1

Get an API key

Create a project-scoped runtime API key in the Opper dashboard.
2

Submit a generation

curl -sX POST https://api.opper.ai/v3/videos \
  -H "Authorization: Bearer $OPPER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/sora-2",
    "prompt": "a hot air balloon drifting over green hills at dawn",
    "parameters": { "seconds": "4", "size": "1280x720" }
  }'
# → 202 { "id": "gen_...", "status_url": "https://api.opper.ai/v3/artifacts/gen_.../status" }
3

Poll until ready, then download

# Poll (repeat until status is "completed" or "failed")
curl -s https://api.opper.ai/v3/artifacts/gen_XXX/status \
  -H "Authorization: Bearer $OPPER_API_KEY"
# processing → { "status": "processing", "provider": "openai", "model": "openai/sora-2" }
# done       → { "status": "completed", "mime_type": "video/mp4", "url": "https://...presigned..." }

# Download the finished clip
curl -s "<url-from-completed-response>" -o video.mp4

Models and parameters

model and prompt are the only fields Opper owns. Everything inside parameters is forwarded verbatim to the provider, which validates and rejects it — so the accepted keys depend on the model. Common examples:
ModelExample parameters
openai/sora-2{ "seconds": "4", "size": "1280x720" }
xai/grok-imagine-video{ "duration": 6, "aspect_ratio": "16:9", "resolution": "720p" }
pruna/wan-t2v{ "resolution": "720p", "aspect_ratio": "16:9" }
vertexai/veo-3.1-fast-generate-001{ "durationSeconds": 4, "resolution": "720p", "generateAudio": false }
To discover what’s available programmatically — including each model’s accepted aspect_ratios, resolutions, and max_duration — call GET /v3/videos/models:
curl -s "https://api.opper.ai/v3/videos/models" \
  -H "Authorization: Bearer $OPPER_API_KEY"
Each item’s capabilities tells you the input modality: video_generation is text-to-video, image_to_video needs a reference image, and video_editing is video-to-video.

Reference image and video

Alongside prompt, you can pass a top-level image (image-to-video) or video (video-to-video). Each is an http(s) URL or a data-URI.
  • image — supported by image_to_video models: openai/sora-2, openai/sora-2-pro, vertexai/veo-3.1-generate-001, vertexai/veo-3.1-fast-generate-001, pruna/wan-i2v, xai/grok-imagine-video.
  • video — supported by video_editing models: pruna/vace.
# image-to-video (Sora): image URL or base64 data-URI
curl -sX POST https://api.opper.ai/v3/videos \
  -H "Authorization: Bearer $OPPER_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "model": "openai/sora-2",
    "prompt": "the cat slowly turns its head and blinks",
    "image": "https://example.com/cat.jpg",
    "parameters": { "seconds": "4", "size": "720x1280" }
  }'
Source-format rules differ per provider:
Providerimage / video accepts
Sorahttp URL or base64/data-URI. The image’s pixel dimensions must equal the requested size.
Veobase64 / data-URI / gs:// URI only — an http URL is not fetched. (A gs:// object must be readable by Opper’s Vertex service account, so base64/data-URI is the reliable choice.)
Pruna, xAIa public, server-fetchable URL only (a data-URI or private URL won’t work).

Reference