Videos
POST /v1/videos, polling, content download, list, and delete.
curl -X POST "$GATEWAY/v1/videos" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "video-default", "prompt": "a serene mountain landscape at sunset", "duration": 8, "aspect_ratio": "16:9", "resolution": "720p" }'POST /v1/videos creates an async generation job and returns a local video_* id. Poll that local id
with GET /v1/videos/{video_id}. Download the generated bytes with
GET /v1/videos/{video_id}/content; the default variant is video.
Request parameters
There is no industry standard for video generation, so the gateway defines its own surface and stays accept-compatible with OpenAI's Sora shape:
| Parameter | Notes |
|---|---|
model, prompt | Required. |
duration | Length in seconds (integer). seconds (string or int) is the OpenAI-style alias; send one or the other. |
size | Exact WIDTHxHEIGHT. Interchangeable with aspect_ratio + resolution; send one form. |
aspect_ratio / resolution | 16:9, 9:16, ... / 480p–4K. Reverse-mapped to an exact size for providers that need one. |
input_references | Array of {type: "image_url"|"audio_url"|"video_url", ...} parts. input_reference (single, image_url or file_id) is the OpenAI-style alias. |
frame_images | First/last frame conditioning (frame_type: "first_frame"|"last_frame") for models that support it. |
seed, generate_audio | Forwarded only when the model profile declares support. |
quality | Gateway extension; validated and forwarded only when the profile declares qualities. |
user | Gateway-side attribution only. It is stored with the job and never forwarded upstream. |
extra_body | Provider-specific passthrough merged into the upstream request body. |
Every parameter is validated against the model profile before routing, so unsupported parameters fail
fast with unsupported_parameter instead of a provider error mid-pool.
Reference images can be sent as data:image/... base64 URLs; large data URLs are redacted before the
request body is persisted. Multipart uploads (the OpenAI SDK's file-typed input_reference) are not
supported — use the JSON reference forms.
Storage
Videos use the gateway-wide object storage layer. Configure OBJECT_STORAGE_BACKEND=local for
development or OBJECT_STORAGE_BACKEND=s3 for S3/R2/MinIO-compatible storage in production. The
gateway stores generated video bytes for 24 hours by default (VIDEOS_ASSET_RETENTION_HOURS=24) and
keeps metadata in Postgres.
Model profiles
Video-capable deployments declare catalogEntry.operations["video.generate"]. The profile controls
accepted durations, sizes (with per-provider aspectRatio/resolution mappings), quality,
reference support (supportsImageUrl, supportsAudioUrl, supportsVideoUrl, supportsFileId,
supportsFrameImages, maxInputReferences), and supportsSeed/supportsGenerateAudio.
Adapters expose video generation through transports: videos (OpenAI-shaped Videos API),
videos_async (async job API: submit /videos, poll /videos/{jobId}, download
/videos/{jobId}/content), and generate_videos (Google long-running operations). Adapter defaults
pick the common path; use transportOverrides when a custom compatible target needs another
transport.
Lifecycle
GET /v1/videoslists videos visible to the caller (virtual keys see their own; the master key sees all).GET /v1/videos/{video_id}refreshes upstream status when needed.GET /v1/videos/{video_id}/contentstreams bytes from object storage and supports byte ranges (including suffix ranges).DELETE /v1/videos/{video_id}deletes stored assets, marks the metadata deleted, and best-effort deletes the upstream job where the provider supports it.
A background poller advances unfinished jobs (VIDEO_JOB_POLL_INTERVAL_MS, batch size
VIDEO_JOB_POLL_BATCH_SIZE) and fails jobs that exceed VIDEO_JOB_MAX_RUNTIME_MINUTES. Jobs are
claimed atomically, so multiple gateway instances can poll safely.
What to read next
- Creating deployments — custom video profiles.
- Providers → OpenAI-compatible — compatible APIs and transport overrides.