Wan
Wan is a video generation model series covering text-to-video, image-to-video, reference-to-video, and video editing, plus audio-driven generation (lip-sync from a driving audio track) and clip continuation. Wan 3.0 is a single general-purpose family that accepts mixed material — keyframes, reference images, video and audio, or a document or web page — in one request, in four quality tiers.
For the image-to-video Spicy models (wan2.7-i2v-spicy, wan2.2-i2v-spicy), see
Wan Spicy.
https://llm.siraya.ai/v1/videos/generations
https://llm.siraya.ai/v1/videos/{video_id}
https://llm.siraya.ai/v1/videos/{video_id}
Synchronous by default, asynchronous on request
By default the request waits for the render and returns the finished video URL. Renders
can take minutes, so async: true is recommended: you get an id back
immediately and poll GET /v1/videos/{video_id} every ~15 seconds until status is
completed or failed. Pass a callbackUrl to be notified instead of polling. See
Asynchronous generation.
Supported Models
| Model ID | Capability | Resolutions | seconds |
|---|---|---|---|
wan2.7-t2v |
Text-to-video, including audio-driven generation via audio_url |
720P, 1080P |
2–15 |
wan2.7-i2v |
Image-to-video — first/last frame, lip-sync driving, and clip continuation | 720P, 1080P |
2–15 |
wan2.7-r2v |
Reference-to-video, with optional per-reference voice | 720P, 1080P |
2–15 |
wan2.7-videoedit |
Video editing from a source clip | 720P, 1080P |
0 or 2–10 |
wan3.0-video |
Wan 3.0 — text, keyframes, reference material, or a document/link | 480p, 720p, 1080p |
2–30, or -1 |
wan3.0-video-pro |
Wan 3.0, high-resolution tier | 1080p, 2k, 4k |
2–30, or -1 |
wan3.0-video-prime |
Wan 3.0 Prime | 480p, 720p, 1080p |
2–30, or -1 |
wan3.0-video-prime-pro |
Wan 3.0 Prime, high-resolution tier | 1080p, 2k, 4k |
2–30, or -1 |
All four Wan 3.0 models share one parameter surface; they differ only in quality tier and resolution range.
Wan 2.7 vs Wan 3.0
The two generations take different request shapes. Wan 2.7 carries its material in the
frame_images / input_references arrays; Wan 3.0 takes every material as its own flat,
top-level field.
| Wan 2.7 | Wan 3.0 | |
|---|---|---|
| Material | frame_images, input_references (by role) |
first_frame, last_frame, reference_images, reference_videos, reference_audios, file, link |
resolution values |
uppercase 720P / 1080P |
lowercase — 480p / 720p / 1080p, or 1080p / 2k / 4k on the -pro tiers |
seconds range |
2–15 (2–10 for video editing) |
2–30, or -1 to let the model choose |
aspect_ratio |
16:9 default |
16:9 · 4:3 · 1:1 · 3:4 · 9:16 · adaptive |
generate_audio default |
not specified | true |
negative_prompt, audio_url, watermark, audio_setting |
supported | not used |
DELETE /v1/videos/{id} |
— | supported on completed tasks |
Moving Wan 3.0 requests off input_references
Wan 3.0 no longer reads role-tagged input_references entries such as
{ "role": "reference_image", "url": ... }. Send the material in the flat fields above instead —
see Wan 3.0 material.
Header
Bearer <API_KEY>).
Body
All Wan parameters are sent flat, at the top level of the request body — there is no settings
or options wrapper, and no extra_body is needed.
wan2.7-t2v.
"blurry, low quality". Wan 2.7 only.
2–15 (2–10 on video editing, where 0 means "follow the
source video without truncation"). Wan 3.0: 2–30, or -1 to let the model choose; when a
reference video is attached, input plus output must stay within 30 s. Wan 3.0 also accepts the
spelling duration; if both arrive, seconds wins.
720P / 1080P (lowercase is rejected with a 400); Wan 3.0 takes lowercase 480p /
720p / 1080p, or 1080p / 2k / 4k on wan3.0-video-pro and wan3.0-video-prime-pro.
16:9. Wan 3.0 takes 16:9, 4:3, 1:1, 3:4, 9:16, or
adaptive, which infers the ratio from the material.
-1 on Wan 2.7, 0 on Wan 3.0 — for a random seed.
false when you want the prompt used verbatim.
Rewriting carries no surcharge on Wan 3.0.
audio; if both arrive, generate_audio wins. Wan 2.7 documents
no explicit default.
wan2.7-t2v.
With no audio_url, text-to-video generates its own background music and sound effects.
auto — the model scores the clip from your prompt — or origin to keep
the source video's audio. Separate from generate_audio.
role — see input_references.
false, the request waits for generation to finish and returns the completed video URL. When true (recommended), it returns immediately with a video id you poll for status. See Asynchronous generation.
async is true. An http(s) URL the router will POST to once generation completes (or fails), so you don't have to poll.
import requests
url = "https://llm.siraya.ai/v1/videos/generations"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer <API_KEY>"
}
data = {
"model": "wan3.0-video",
"prompt": "A slow pan over a mountain range at sunrise",
"seconds": 5,
"resolution": "720p",
"aspect_ratio": "16:9",
"async": True
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
Example Response
With "async": true, the job is accepted immediately:
{
"id": "video_8fK2mQxR7pLnVwZ3tYbC...",
"object": "video",
"status": "processing",
"model": "wan3.0-video",
"seconds": 5,
"usage": { "completion_tokens": 0, "total_tokens": 0 }
}
Without async, the request waits and returns the finished video:
Media inputs
Wan 2.7
frame_images
Hard constraints on the opening and closing frame of an image-to-video render.
| Field | Type | Description |
|---|---|---|
frame_type |
string | first_frame or last_frame. |
image_url |
string | Public URL or a base64 data URL. |
input_references
Everything else. Each entry carries a role and a url; role is what decides how the material is
used:
role |
Used by | Meaning |
|---|---|---|
reference_image |
wan2.7-r2v |
Soft subject/style guidance |
video |
wan2.7-videoedit |
The source clip being edited — required, exactly 1 |
driving_audio |
wan2.7-i2v |
Lip-sync driving audio, paired with a first_frame |
first_clip |
wan2.7-i2v |
A prior clip to continue from |
An entry may also carry voice_url, an audio attachment on that specific reference rather than a
material of its own. Reference-to-video uses it to give a reference image a matching voice:
{ "role": "reference_image", "url": "https://your-domain.com/girl.jpg", "voice_url": "https://your-domain.com/girl-voice.mp3" }
Wan 3.0 material
Each kind of material has its own top-level field:
| Field | Type | Limits |
|---|---|---|
first_frame / last_frame |
string | URL or base64. JPEG, PNG (no alpha), BMP or WEBP; 240–8000 px per side; aspect ratio ≤ 8:1; ≤ 20 MB |
reference_images |
array | Up to 10 entries, URL or base64; same image limits as above |
reference_videos |
array | Up to 5 entries, URL only; mp4 or mov, each 1–15 s, ≤ 100 MB |
reference_audios |
array | Up to 5 entries, URL only; wav or mp3, each 1–15 s, ≤ 15 MB |
file |
string | A document: docx, doc, xlsx, xls, pptx, ppt, pdf, txt, key, pages, numbers or md; ≤ 100 MB |
link |
string | A public web page URL (no authentication) |
The material picks one of three mutually exclusive modes — a request mixing them is rejected:
- Keyframe —
first_frameand/orlast_frame. - Reference — any of
reference_images,reference_videos,reference_audios, combined freely. The prompt can address each input by position:"Image 1","Video 1","Audio 1". - Document —
fileorlink, one of the two.
With no material at all, the request is plain text-to-video.
Examples
Audio-driven text-to-video (Wan 2.7)
{
"model": "wan2.7-t2v",
"prompt": "A rapper performing on stage",
"audio_url": "https://your-domain.com/track.mp3",
"resolution": "720P",
"watermark": false
}
Lip-sync from a portrait (Wan 2.7)
{
"model": "wan2.7-i2v",
"prompt": "The person lip-syncs to the audio",
"frame_images": [
{ "frame_type": "first_frame", "image_url": "https://your-domain.com/portrait.png" }
],
"input_references": [
{ "role": "driving_audio", "url": "https://your-domain.com/track.mp3" }
],
"resolution": "720P",
"watermark": false
}
Continuing a clip (Wan 2.7)
seconds here is the total length after continuation, not the length of the new footage.
{
"model": "wan2.7-i2v",
"prompt": "Continue the scene",
"input_references": [
{ "role": "first_clip", "url": "https://your-domain.com/clip1.mp4" }
],
"seconds": 10,
"resolution": "720P",
"watermark": false
}
Video editing (Wan 2.7)
{
"model": "wan2.7-videoedit",
"prompt": "Change the style to a watercolor painting",
"input_references": [
{ "role": "video", "url": "https://your-domain.com/input.mp4" }
],
"audio_setting": "origin",
"resolution": "720P",
"watermark": false
}
Leave seconds at 0 to keep the source length untouched; a value between 2 and 10 truncates.
Wan 3.0 first and last frame
{
"model": "wan3.0-video",
"prompt": "The flower slowly blooms",
"first_frame": "https://your-domain.com/bud.jpg",
"last_frame": "https://your-domain.com/bloom.jpg",
"resolution": "1080p",
"async": true
}
Wan 3.0 with reference material
{
"model": "wan3.0-video-pro",
"prompt": "The woman in Image 1 dances to Audio 1, moving like the dancer in Video 1",
"reference_images": ["https://your-domain.com/girl.jpg"],
"reference_videos": ["https://your-domain.com/dance.mp4"],
"reference_audios": ["https://your-domain.com/track.mp3"],
"resolution": "4k",
"async": true
}
Wan 3.0 from a document, with automatic duration
{
"model": "wan3.0-video-prime",
"prompt": "Turn this deck into a short product explainer",
"file": "https://your-domain.com/deck.pptx",
"seconds": -1,
"resolution": "720p",
"async": true
}
Poll for status
https://llm.siraya.ai/v1/videos/{video_id}
When you submit with async: true, call the status endpoint with the returned id until status
reads completed or failed. Poll roughly every 15 seconds and back off on 429.
{
"id": "video_8fK2mQxR7pLnVwZ3tYbC...",
"object": "video",
"status": "completed",
"model": "wan3.0-video",
"seconds": 5,
"resolution": "720p",
"output_url": "https://.../result_00.mp4",
"usage": { "completion_tokens": 0, "total_tokens": 0 }
}
| Field | Present | Meaning |
|---|---|---|
id |
always | Opaque — pass it as-is to the status and delete endpoints; don't parse it |
status |
always | processing · completed · failed |
seconds, resolution |
completed | On Wan 3.0, echoed from your request — see Behavior worth knowing |
output_url |
completed | Signed and expiring — download promptly rather than storing it as a stable link |
error |
failed | { "code": "...", "message": "..." } |
usage |
always | Always zero — Wan has no token concept |
Once status is completed you can also stream the raw bytes from
GET /v1/videos/{video_id}/content.
Delete a task
https://llm.siraya.ai/v1/videos/{video_id}
Wan 3.0 only. Deletes a completed task:
{
"id": "video_8fK2mQxR7pLnVwZ3tYbC...",
"object": "video",
"deleted": true,
"deleted_at": "2026-10-21T08:15:02Z",
"model": "wan3.0-video"
}
A task that is still processing answers 409; a failed task is refused too. Deletion is not
retried for you.
Behavior worth knowing
Wan 3.0 seconds and resolution are echoes, not measurements. The finished task carries
neither, so the status response reports what you asked for at create time. With seconds: -1 the
real length is whatever the model chose.
Wan 3.0 modes don't mix. Keyframe fields, reference fields, and file / link are mutually
exclusive — a request combining them is rejected. See Wan 3.0 material.
Material URLs must be public. Reference material is fetched by the model service itself; a URL behind authentication fails the task with a download error.
Prefer URLs over base64 for large material. The request-body size limit applies to the whole payload, and a couple of base64 images can exceed it. Video and audio references are URL-only regardless.
Video editing ignores a requested duration. The output length follows the source clip
(seconds: 0 on Wan 2.7 video editing means exactly that), so the seconds in the status response
reflects the source, not a number you controlled.
prompt_extend is on by default. Your prompt is rewritten before generation unless you send
"prompt_extend": false. Turn it off when you need a literal reading of the prompt or reproducible
output alongside a fixed seed.
Errors
A request-time refusal is final — it means the parameters can't work together, not that the service is unavailable. Retrying the same body won't help. The model's own validation message is passed through wherever it is clear.
| Status | Meaning |
|---|---|
400 |
An invalid value or unsupported combination — an out-of-range seconds (e.g. duration must be between 2 and 30…), a resolution in the wrong case or outside the model's tier, mixed Wan 3.0 modes, or a missing required field |
401 |
Invalid API key |
404 |
Unrecognized model code |
409 |
DELETE on a task that is not completed |
200 with status: "processing" |
Accepted — keep polling. A task that fails after starting reports status: "failed" with an error object |