Wan 3.0 API: Text-to-Video and Image-to-Video in Python
One script made both clips: the code, the real times and Alibaba's per-second price.
On this page
- Is there an official Wan 3.0 API, and which model should I use?
- What do you need before the first call?
- Which parameters matter?
- What does the Python code look like?
- What did the two calls produce?
- Text to video: the forge
- Image to video: the paper boat
- Is the sound on, and does "no music" work?
- How do you get the video file, and how long do links last?
- Which errors will you hit?
- How much does a Wan 3.0 clip cost?
- Frequently asked questions
- How long does a call take?
- How do I turn the sound off?
- Should I use wan3.0-video or wan3.0-video-prime?
- How long does the video link last?
- Sources checked
Wan 3.0 runs on Alibaba Cloud Model Studio as wan3.0-video and the faster wan3.0-video-prime. Every call is asynchronous: create a task, poll the ID, download the MP4. Our Python script made a 5-second 720P clip from text in 2 min 42 s and one from a still in 3 min 20 s, both with sound.
- Put your key in
OMNIAKEY_API_KEY. - POST
https://api.omniakey.com/v1/media/taskswith the model, the operation, the prompt, the parameters and a newIdempotency-Key. - Poll
GET /v1/media/tasks/{id}until the status reads succeeded, then downloadassets[0].urlat once.
Is there an official Wan 3.0 API, and which model should I use?
Yes. Alibaba Cloud Model Studio is the official API, with both wan3.0-video and wan3.0-video-prime (reference updated October 15, 2026). Its create call needs an X-DashScope-Async: enable header, and Alibaba's Python path is the DashScope SDK 2.0.1 or newer.
| Alibaba Model Studio | OmniaKey | |
|---|---|---|
| Both model IDs | Yes | Yes |
| Async header needed | Yes | No |
| Video link lasts | 24 hours | About 1 hour, renewable |
| Billed | Per second | Per second |
| Python | DashScope SDK | Standard library |
Both IDs take one body shape, and the model picks the mode from the media you send. The script below runs wan3.0-video, and its MODEL line switches it. We did not run Wan 3.0 Prime, which OmniaKey's docs describe as the same capabilities at roughly half the turnaround (checked October 31, 2026).
What do you need before the first call?
Three things, and the first one is the key:
-
An OmniaKey API key, exported in your shell:
bashexport OMNIAKEY_API_KEY="your-key" -
Python 3. The script imports the standard library only, so python3 runs it as is.
-
For image to video, a first frame: a JPEG about 1024 px wide, or a public HTTPS URL. The script refuses a file over 700,000 bytes, because Base64 adds a third and the body cap is 1 MiB (docs, checked October 31, 2026).
Which parameters matter?
Seven fields do most of the work, and each is a value inside parameters.
| Parameter | What it does | Default |
|---|---|---|
| Duration | Clip length, seconds | 5 |
| Resolution | Picture size tier | 1080P |
| Ratio | Frame shape | adaptive |
| Audio | Sound track | on |
| Seed | Repeatability hint | -1 |
| Prompt extend | Rewrites your prompt | on |
| Watermark | Adds a corner mark | off |
The script sets duration, resolution and ratio. It asks for 720P, which costs half as much per second at list prices as Alibaba's 1080P default.
What does the Python code look like?
The script below ran unchanged on October 31, 2026: standard library only, both modes, one MODEL line to change.
import base64
import json
import os
import time
import urllib.error
import urllib.request
import uuid
API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "wan3.0-video"
def request(method, url, body=None, extra_headers=None):
headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
data = None
if body is not None:
headers["Content-Type"] = "application/json"
data = json.dumps(body).encode()
headers.update(extra_headers or {})
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.load(resp)
def poll(url, attempts=5):
for attempt in range(attempts):
try:
return request("GET", url)
except urllib.error.HTTPError as err:
if err.code < 500 or attempt == attempts - 1:
raise
except urllib.error.URLError:
if attempt == attempts - 1:
raise
time.sleep(5 * (attempt + 1))
def run_task(body, out_path):
task = request("POST", API, body, {"Idempotency-Key": str(uuid.uuid4())})["id"]
print("task", task, flush=True)
for _ in range(180): # 5-second polls, up to 15 minutes
time.sleep(5)
state = poll(f"{API}/{task}")
if state["status"] not in ("queued", "processing"):
break
else:
raise TimeoutError(f"{task} is still {state['status']}: poll it again later, do not resubmit")
if state["status"] != "succeeded":
raise RuntimeError(state.get("error") or state["status"])
asset_url = state["assets"][0]["url"] # signed link: short-lived, so download now
req = urllib.request.Request(asset_url, headers={"User-Agent": "omniakey-example/1"})
with urllib.request.urlopen(req, timeout=300) as resp, open(out_path, "wb") as f:
f.write(resp.read())
return task
def text_to_video(prompt, out_path, duration=5, resolution="720P", ratio="16:9"):
body = {
"model": MODEL,
"type": "video",
"operation": "text_to_video",
"input": {"prompt": prompt},
"parameters": {"duration": duration, "resolution": resolution, "ratio": ratio},
}
return run_task(body, out_path)
def image_to_video(prompt, image_path, out_path, duration=5, resolution="720P"):
with open(image_path, "rb") as f:
raw = f.read()
if len(raw) > 700_000: # base64 adds a third, and the whole body must stay under 1 MiB
raise ValueError("first frame too large: save it as a JPEG about 1024 px wide")
frame = "data:image/jpeg;base64," + base64.b64encode(raw).decode()
body = {
"model": MODEL,
"type": "video",
"operation": "image_to_video",
"input": {"prompt": prompt, "media": [{"type": "first_frame", "url": frame}]},
"parameters": {"duration": duration, "resolution": resolution, "ratio": "adaptive"},
}
return run_task(body, out_path)
if __name__ == "__main__":
print("done", text_to_video(
"A blacksmith hammers a glowing horseshoe on an anvil in a dark forge. Sparks fly at each "
"strike and light his leather apron. The camera slowly pushes in. Sound of the hammer ringing "
"on steel and the fire crackling. No dialogue, no music, no text.",
"forge.mp4",
))
print("done", image_to_video(
"Image 1 is the first frame. The paper boat drifts slowly to the right across the puddle. "
"Light rain makes small ripples and the cafe lights shimmer in the water. The camera stays "
"low and still. Sound of light rain. No dialogue, no music, no text.",
"boat.jpg",
"boat-drifts.mp4",
))
What each part does:
run_taskmints a newIdempotency-Keyfor each job. Resending the same key with the same body returns the original task and never charges twice (docs, checked October 31, 2026).- It polls every 5 seconds for up to 15 minutes, then raises TimeoutError.
- A timeout means poll the same ID again later; a resubmit mints a new key, creates a second job and bills it.
- It downloads the first asset URL at once, because the signed link is short-lived.
image_to_videorefuses a frame over 700,000 bytes: Base64 adds a third, and the body cap is 1 MiB.- The image call sets ratio to
adaptive, so the clip follows the still's shape.
What it printed:
task task_<id>
done task_<id>
task task_<id>
done task_<id>
What did the two calls produce?
Both files came back as 5.04-second MP4s, 150 frames at 30 fps, H.264, with an AAC stereo track at 44.1 kHz.
Text to video: the forge

The clip follows the prompt: a blacksmith in a dark shirt and leather apron hammers a glowing orange horseshoe, sparks burst at 2.2 seconds, and the camera pushes in a little. The flaw is a stamped maker's mark of garbled letters on the anvil, though the prompt asked for no text. Start to file took 2 min 42 s; the MP4 is 1280×720 at 6.6 MB.
Image to video: the paper boat

The first frame was a still we made with Nano Banana 2.1, a red paper boat on a rain puddle, resized to a 1024×571 JPEG of 158 KB and sent inline as a data URL. The clip keeps that dusk light and the wet cobblestones, drifts the boat left to right as asked, ripples at 1.6 seconds, and holds the camera low and still. It came back as 1284×716 because adaptive followed the still's shape, in 3 min 20 s at 7.4 MB.
Is the sound on, and does "no music" work?
Sound is on by default. Gemini 3.8 Flash described the forge track as metallic clinking with no speech and no music, and the paper-boat track as a melancholic, calm piano melody, although that prompt ended with "no music". Alibaba's prompt guide (updated October 16, 2026) suggests writing "No BGM" or "No background music", and our prompt used neither.
With "audio": false the file carries a video track only: our 2-second 480P lantern job had no sound track, and Alibaba charges the same either way.
| Clip | Time | Size | Sound |
|---|---|---|---|
| Forge (text) | 2 min 42 s | 1280×720 | Clinking, no music |
| Paper boat (image) | 3 min 20 s | 1284×716 | Piano despite "no music" |
| Lantern, audio off | 4 min 36 s | 854×480 | No sound track |
Queue time varies: the 2-second audio-off job took 4 min 36 s, longer than either 5-second 720P clip. For prompt wording, the Wan 3.0 prompt guide has the structure and example prompts.
How do you get the video file, and how long do links last?
Poll GET /v1/media/tasks/{id} until the status reads succeeded, failed or canceled; while the job runs it reads queued or processing. A finished task returns a signed asset URL that lasts about an hour (OmniaKey docs, checked October 31, 2026). Download it at once, then poll the task again for a fresh URL whenever the old one expires, because the record lives for 24 hours.
The file is an MP4 with H.264 video at 30 fps, and Alibaba's own video URL lasts 24 hours. Cancelling a Wan 3.0 job does not stop the render, and a job that succeeds after a cancel is still billed, so check duration and resolution before you submit.
Which errors will you hit?
Most of these come back before a task exists, and each has a fix in the request or the key.
- 400
model_price_error— duration outside 2 to 30 seconds. Our"duration": 1probe failed in 0.9 s with "media duration must be between 2 and 30 seconds"; no task was created and nothing was billed. - 400
missing_idempotency_key— no Idempotency-Key header. Add one, up to 255 characters. - 409
idempotency_key_reused— same key, different body. Mint a new key for each prompt. - 403
model_not_allowed— the key may not call that model. Check themodelvalue, then the key's settings. - 403 with a balance or spending-cap message — low balance or a per-key cap. Top up or raise the cap.
- 404
task_not_found— wrong ID, or a task over 24 hours old. Poll the ID the create call returned. - 409
task_state_conflict— the job already finished, as when a cancel lands after success. Read the status first. - 429 — too many requests. OmniaKey publishes no fixed rate limits, so back off with exponential delay and jitter.
- 503
no_available_channel— no channel for that operation, such as video to video. Use text to video or image to video. TimeoutError— still running after 15 minutes. Poll the same ID later; a resubmit makes and bills a second job.
How much does a Wan 3.0 clip cost?
Alibaba bills per second of video, and a failed request is not billed (pricing page updated October 29, 2026). The table holds Alibaba's Singapore list prices per second, checked October 31, 2026, from Alibaba's Model Studio pricing page.
| Model | 480P | 720P | 1080P |
|---|---|---|---|
| Wan 3.0 | $0.05 | $0.1 | $0.2 |
| Wan 3.0 Prime | $0.068 | $0.14 | $0.28 |
A 5-second 720P clip is $0.50 on Wan 3.0 (5 × $0.1) and $0.70 on Prime (5 × $0.14). The three Wan 3.0 prices carry a "Limited-time 30% off" marking, and the page does not say whether the figures include it. Sound on or off costs the same.
The free quota is 30 seconds of video, input plus output, on wan3.0-video in Singapore; Prime has none. China (Beijing) lists lower dollar rates for the standard model: $0.041256, $0.082513 and $0.165025 per second at 480P, 720P and 1080P.
OmniaKey bills per second too, with current rates on the Wan 3.0 and Wan 3.0 Prime model pages.
Frequently asked questions
How long does a call take?
Alibaba says a job typically takes 1 to 5 minutes and suggests polling every 15 seconds (reference, checked October 31, 2026). Our three jobs took 2 min 42 s, 3 min 20 s and 4 min 36 s.
How do I turn the sound off?
Set "audio": false inside parameters, and the MP4 arrives with a video track only, as our lantern job did. The price stays the same.
Should I use wan3.0-video or wan3.0-video-prime?
Pick wan3.0-video for Alibaba's lower list rate and its 30-second free quota in Singapore, and Prime when turnaround matters more. OmniaKey describes Prime as the same capabilities at roughly half the time.
How long does the video link last?
About an hour on OmniaKey, and polling the task again returns a fresh link while the record lasts 24 hours. Alibaba's own video URL lasts 24 hours.
Sources checked
- Wan 3.0 video generation API reference, checked October 31, 2026
- Wan 3.0 video generation guide, checked October 31, 2026
- Wan 3.0 video generation prompt guide, checked October 31, 2026
- Alibaba Cloud Model Studio model pricing, checked October 31, 2026
- OmniaKey video API docs, checked October 31, 2026
- OmniaKey media API overview, checked October 31, 2026
- OmniaKey API error codes, checked October 31, 2026
Models in this article
Related articles
Wan 3.0 Prompt Guide: Structure, Examples and Real Clips
Five prompts, five real clips: what Wan 3.0 followed, what it skipped and how to fix it.
Wan 3.0 vs Wan 2.7
Wan 3.0 is the practical choice for a new OmniaKey video workflow; keep Wan 2.7 only where its older, task-specific API is already part of your production contract.
Kling 3.0 vs Wan 3.0: Same-Prompt Test and Price
Three prompts, two video models, one day: what each made and what it cost.
Recent posts
- Claude Code 2.0: Release Date, New Features and How to Update
- Seedream 5.0 Pro vs Nano Banana Pro: Same-Prompt Test and Price
- Suno v6 Review: Real Songs, Speed and How It Compares to v4.5
- Codex Image Generation With a Custom Provider: imagegen Setup
- Factory Droid Custom Models: Use Claude and GPT With Your Own API Key

