Video Generation
Video generation lets applications submit prompt-to-video tasks through AISIX while keeping caller authentication, model aliases, upstream credentials, rate limits, and content guardrails in one gateway path.
AISIX exposes an OpenAI-compatible video surface with three routes that mirror the provider-side asynchronous workflow: submit a task, poll its status, and download the result. The gateway holds no task state — the returned video ID encodes everything AISIX needs to route later status and download calls to the right provider.
In this guide, you will generate a video through AISIX using an Alibaba Model Studio video model and follow the task to a downloadable result.
Prerequisites
Before starting, prepare the following:
- A running AISIX gateway that can serve proxy requests.
- A caller API key that can access the video model alias.
- A model alias whose configured provider is one of the supported video providers (see Endpoint Behavior). Every provider except OpenAI needs a provider key whose
api_basereaches the provider's API — there is no built-in default base URL for them. An OpenAI model falls back to the standard OpenAI base URL whenapi_baseis unset. The examples below use an Alibaba Model Studio model.
The examples use a model alias configured like the following. The upstream model name is a text-to-video model from the provider's catalog:
{
"display_name": "wan-video-prod",
"model_name": "wan2.7-t2v",
"provider_key_id": "YOUR_PROVIDER_KEY_ID"
}
Export the gateway connection and request values:
# AISIX_PROXY has no trailing slash or endpoint path such as /v1.
# The local quickstarts use http://127.0.0.1:3000.
export AISIX_PROXY="YOUR_AISIX_GATEWAY_ORIGIN"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="wan-video-prod"
Create a Video Generation Task
Submit the task with the model alias, a prompt, and optionally a duration in seconds:
curl -sS -X POST "${AISIX_PROXY}/v1/videos" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${AISIX_MODEL}"'",
"prompt": "A miniature city built from cardboard comes alive at night.",
"seconds": 5
}'
AISIX resolves the alias, runs input guardrails on the prompt, reserves rate-limit capacity, and submits the task to the provider asynchronously. The response is a video job object:
{
"id": "bW9kZWwtaWQtMTpkMkZ1TFhacFpHVnZMWEJ5YjJROnRhc2stMDE",
"object": "video",
"model": "wan-video-prod",
"status": "queued",
"progress": 0,
"created_at": 1753257600,
"seconds": "5"
}
The id value is an opaque gateway-issued video ID. Store it — the status and download routes take it as the path parameter.
Request fields:
| Field | Required | Meaning |
|---|---|---|
model | Yes | The AISIX model alias. |
prompt | Yes | The text prompt for the video. |
seconds | No | Video duration in seconds, as an integer or a numeric string. Forwarded as the provider's own duration parameter — see Parameter Mapping. |
size | No | Pixel dimensions as WIDTHxHEIGHT, for example 1280x720. Each provider expresses output dimensions differently and validates the value against its own per-model list, so check Parameter Mapping and the provider's model documentation before setting it. |
Unset optional fields are omitted from the upstream request entirely.
Poll the Task Status
Poll the task with the video ID until the status reaches a terminal value:
curl -sS "${AISIX_PROXY}/v1/videos/YOUR_VIDEO_ID" \
-H "Authorization: Bearer ${AISIX_API_KEY}"
A finished task reports completed and, when the provider states it, the actual video duration:
{
"id": "bW9kZWwtaWQtMTpkMkZ1TFhacFpHVnZMWEJ5YjJROnRhc2stMDE",
"object": "video",
"model": "wan-video-prod",
"status": "completed",
"progress": 100,
"created_at": 0,
"seconds": "5"
}
The status field is a four-value enum:
| Status | Meaning |
|---|---|
queued | The provider accepted the task and has not started it. |
in_progress | The provider is generating the video. |
completed | The video is ready to download. |
failed | Generation failed, was canceled, or the provider no longer knows the task (for example, an expired task). The response carries an error object with the provider's code and message when available. |
AISIX normalizes each provider's own task states onto that enum. Some providers report no distinct queued state, so a submission there starts directly at in_progress:
provider value | queued | in_progress | completed | failed |
|---|---|---|---|---|
alibaba | PENDING | RUNNING | SUCCEEDED | FAILED, CANCELED, UNKNOWN, or any other state |
zhipuai | Not reported — a task starts at in_progress | PROCESSING | SUCCESS | FAIL or any other state |
volcengine | queued | running | succeeded | failed, cancelled, expired, or any other state |
runwayml | PENDING, THROTTLED | RUNNING | SUCCEEDED | FAILED, CANCELLED, or any other state |
openai | queued | in_progress | completed | failed or any other state |
progress reports a real completion percentage for providers that expose one (OpenAI Sora). For providers that do not, it reports 0 until the task completes and 100 afterward. Because the gateway stores no task state, created_at is populated on the submit response only; poll responses report 0.
Download the Video
When the status is completed, request the content route. Use curl -L so the command works for every provider — AISIX either redirects to the provider's download URL or streams the video itself, depending on how the provider delivers finished files:
curl -sS -L -o video.mp4 \
"${AISIX_PROXY}/v1/videos/YOUR_VIDEO_ID/content" \
-H "Authorization: Bearer ${AISIX_API_KEY}"
Both paths save the same MP4. The difference matters when you script around the response:
| Delivery | Providers | What the content route returns |
|---|---|---|
| Redirect | Alibaba, Zhipu, Volcengine Ark, Runway | 302 with a Location header pointing at the provider's signed download URL. The transfer goes directly from the provider's storage to the client and does not pass through the gateway. AISIX only redirects to absolute http or https URLs. |
| Gateway stream | OpenAI | 200 with the MP4 bytes, the provider's Content-Type (normally video/mp4), and a Content-Disposition attachment header. The provider requires its own credential to download the file, so AISIX fetches it with the configured provider key and streams the bytes through. The provider credential is never exposed to the caller. |
Streamed responses pass through the gateway chunk by chunk rather than being held in memory, so a large file does not grow the gateway's memory use. Per-chunk reads are bounded by the model's stream timeout: if a slow upstream stalls, the transfer is cut mid-body. When the provider declares a Content-Length, the gateway relays it, so an interrupted transfer surfaces to the client as a short read against that length — retry the content request.
To inspect which path a provider uses, ask curl for the status without following redirects:
curl -sS -o /dev/null -w "%{http_code} %{redirect_url}\n" \
"${AISIX_PROXY}/v1/videos/YOUR_VIDEO_ID/content" \
-H "Authorization: Bearer ${AISIX_API_KEY}"
A redirect provider prints the redirect status and the provider-hosted URL:
302 https://provider-cdn.example.com/videos/task-01/out.mp4
A gateway-stream provider prints 200 with an empty redirect URL. On that path the probe transfers the whole file to /dev/null, so run it against a small task:
200
If the task is not finished, the content route returns 400 with a message telling the caller to keep polling. If the task failed, it returns 400 with the provider's failure detail. An error from the provider's download endpoint is always returned as a JSON error envelope, never as a truncated video body.
Rate Limits and Guardrails
Before a task reaches the provider, the submit route reserves the caller API key layers and the model's limits, as it does for other modeled routes. Model limits include the inline rate_limit and any model-scope rate limit policies. See API Key and Model Rate Limits and Rate Limit Policies.
The status and content routes reserve only the caller API key layers. Task polling is deliberately exempt from model-level limits: a client that submits a task and then hits the model's submission cap can still poll that task to completion. For gateway-stream providers this also means the video bytes transit the gateway without counting against the model's limits — size the gateway's egress accordingly.
Input guardrails resolved for the request — whether attached to the model, the caller API key, the team, or the environment — scan the prompt before submission. A blocked prompt is rejected before any provider task is created and does not consume the model's rate-limit capacity.
Endpoint Behavior
- If the provider key's
api_baseends with the provider's OpenAI-compatible or versioned suffix (/compatible-mode/v1,/api/v1, or/v1for Alibaba;/api/paas/v4for Zhipu;/api/v3for Volcengine Ark), AISIX derives the provider root automatically — an existing key configured for chat traffic works unchanged. Runway's documented base is the bare host, and OpenAI accepts either the bare host or a/v1base. - The submit route requires a JSON media type, such as
application/json. The video create helper in the OpenAI Python SDK sendsmultipart/form-dataon every call, even without a reference asset, so it cannot drive this route — submit with an ordinary HTTP client. The two GET routes are plain GETs and have no such constraint. - OpenAI is the only video provider with a built-in default base URL: an OpenAI model with no
api_baseresolves to the standard OpenAI API. Every other provider requiresapi_baseon the provider key. - Each submission that reaches a provider is recorded in usage logs with zero tokens. A request rejected before dispatch — malformed JSON, or a provider outside the allowlist — emits no usage event. Duration-based cost accounting for video tasks is not yet applied to budgets.
- Submission is not at-most-once. AISIX retries a send-phase transport failure or an upstream
5xx, and whether the first attempt reached the provider is unknowable, so a retry can start a second billable task whose ID the caller never sees. AISIX deliberately does not retry once the provider has responded and only the body failed to read or decode.
Supported Providers
AISIX dispatches the video routes on the model alias's own provider value, not on the upstream model name; the provider key attached to the alias supplies the credential and api_base. The routes accept direct aliases only — a routing or ensemble alias returns 400.
AISIX keeps no allowlist of model IDs. It forwards the configured upstream model name through the fixed mapping below, so a generation still depends on that model accepting the resulting request shape. Check the provider's current catalog, and that model's own parameter rules, before creating an alias.
provider value | Provider setup | Video models | Delivery |
|---|---|---|---|
alibaba | Qwen (Alibaba Cloud) | Model Studio Wan and HappyHorse text-to-video, such as wan2.7-t2v, wan2.2-t2v-plus, and happyhorse-1.1-t2v | Redirect |
zhipuai (zhipu also accepted) | Zhipu AI | CogVideoX, such as cogvideox-3 | Redirect |
volcengine | Volcengine Ark | Ark Seedance, such as doubao-seedance-2-0-260128 | Redirect |
runwayml (runway also accepted) | RunwayML | Runway Gen and Runway-hosted models on the text-to-video endpoint, such as gen4.5, veo3.1, and seedance2 | Redirect |
openai | OpenAI | Sora: sora-2 and sora-2-pro | Gateway stream |
OpenAI deprecated the Videos API and the Sora 2 models on March 24, 2026 and will remove them from the API on September 24, 2026. Aliases backed by sora-2 or sora-2-pro stop working on that date.
A model alias whose provider is not in this table returns 501 not_implemented on submit. Reach those providers' native video APIs through a passthrough route instead.
Two provider values that serve chat traffic are deliberately outside this list: alibaba-cn and zai. Both reach a different API root than their video-capable counterpart, so a video alias must use alibaba or zhipuai.
Parameter Mapping
AISIX maps the unified seconds and size fields onto each provider's own parameters. The mapping is per provider, not per model: AISIX does not inspect which model family the alias names, so where a provider's newer models expect different parameters, omitting the unified field is the caller's job. A field the provider cannot express at all is dropped rather than translated into a different parameter, and the provider validates whatever it receives against its own per-model list.
provider value | seconds maps to | size maps to |
|---|---|---|
alibaba | parameters.duration | parameters.size as WIDTH*HEIGHT. This matches the Wan 2.6 and earlier request protocol. Wan 2.7 models replaced size with resolution and ratio tiers; AISIX still forwards whatever you send, so omit size yourself on a Wan 2.7 alias and let the provider default apply. |
zhipuai | duration | size as WIDTHxHEIGHT, forwarded verbatim |
volcengine | duration | Not forwarded. Ark expresses output dimensions as resolution and ratio quality tiers, which cannot carry an arbitrary WIDTHxHEIGHT. AISIX validates the format and then drops the value, so the provider default applies. The submit response still echoes the size you sent, which does not mean Ark used it; poll responses omit it. |
runwayml | duration | ratio as WIDTH:HEIGHT. AISIX only swaps the separator; Runway validates the result against its per-model resolution list. |
openai | seconds, rendered as a string. OpenAI's create-video schema accepts 4, 8, or 12. | size as WIDTHxHEIGHT, forwarded verbatim. The schema lists 720x1280, 1280x720, 1024x1792, and 1792x1024, but OpenAI publishes a narrower set per model, so check the model's own page. AISIX validates only the WIDTHxHEIGHT syntax. |
Request Fields the Routes Do Not Model
The modeled routes cover text-to-video generation. Fields other than model, prompt, seconds, and size are ignored rather than rejected, so a request carrying them still generates a video — from the prompt alone.
input_referenceis ignored. Image-to-video and video-to-video generation are not modeled on these routes.- Provider-native generation controls, such as a negative prompt, a seed, a reference image, or Wan 2.7's
resolutionandratiotiers, have no unified field and are not forwarded. POST /v1/videos,GET /v1/videos/{video_id}, andGET /v1/videos/{video_id}/contentare the only modeled video routes AISIX serves. Provider routes that list, delete, remix, edit, or extend a video are not modeled, and neither is any provider-specific route beyond generation.
Configure a passthrough route when a caller needs any of these — it reaches the provider's native video API with the gateway still holding the credential and the caller key's access rules.
Errors
The table lists the statuses AISIX itself produces. A provider's own 4xx keeps its status and is relayed in an upstream error envelope; a provider 5xx, a transport failure, or a response AISIX cannot decode becomes 502; an upstream timeout becomes 504; a request body over the size limit becomes 413.
How a failed download surfaces depends on the delivery mode. On gateway-stream delivery, AISIX checks the provider's content endpoint before it starts the transfer, so a failure there is a JSON envelope; a stream cut after the response headers are sent is not, and the caller sees a short read against the declared Content-Length when the provider supplied one. On redirect delivery, AISIX never fetches the file: it returns the absolute http or https URL the provider reported, without verifying it, so anything that fails after the client follows the redirect comes from the provider or its CDN, in whatever format they use.
| Status | When |
|---|---|
400 | The request is malformed: seconds is not a positive integer, or size is not WIDTHxHEIGHT. The content route also returns 400 when the task is still running, with a message telling the caller to keep polling, and when the task failed, with the provider's failure detail. |
401 | The caller API key is missing or invalid. |
403 | On submit, the caller API key is not allowed to use the model alias, or the request comes from a client IP outside the model's allowlist. The error type is permission_denied; an IP rejection also carries the ip_restricted code. |
404 | On submit, the model names no alias the gateway knows; the error type is model_not_found. On the GET routes, the video ID is unknown or malformed, or it belongs to a model the caller key cannot access; the error type is video_not_found. The GET routes fold both an ACL denial and a not-implemented provider into 404, so an ID cannot be used to probe which models exist. |
422 | An input guardrail blocked the prompt. No provider task is created and no rate-limit capacity is consumed. |
429 | A rate limit or a budget rejected the request. Submissions count against both the caller key layers and the model's limits; status and content calls count against the caller key layers only. The caller's budget check applies to all three routes, so an over-budget caller cannot poll or download a task it already paid to submit. |
501 | The model alias resolves to a provider outside the video route's allowlist. The error type is not_implemented. |
A task that the provider reports as failed is not an HTTP error on the status route: GET /v1/videos/{video_id} returns 200 with "status": "failed" and an error object carrying the provider's code and message.
Next Steps
You have now generated a video through the gateway's modeled video surface. For provider video APIs that AISIX has not modeled yet, configure a passthrough route — on inject-mode routes, model-level rate limits apply there as well when the request body names a configured model.