curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
"resolution": "720P",
"size": "16:9",
"duration": 5
}'
import requests
url = "https://api.apimart.ai/v1/videos/generations"
payload = {
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
"resolution": "720P",
"size": "16:9",
"duration": 5,
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://api.apimart.ai/v1/videos/generations";
const payload = {
model: "wan3.0-video",
prompt: "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
resolution: "720P",
size: "16:9",
duration: 5,
};
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.apimart.ai/v1/videos/generations"
payload := map[string]interface{}{
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop",
"resolution": "720P",
"size": "16:9",
"duration": 5,
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01J9HA7JPQ9A0Z6JZ3V8M9W6PZ"
}
]
}
{
"error": {
"code": 400,
"message": "Invalid request parameters",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed, please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient account balance, please top up and try again",
"type": "payment_required"
}
}
{
"error": {
"code": 429,
"message": "Too many requests, please try again later",
"type": "rate_limit_error"
}
}
Wan3.0
Wan3.0 Video Generation
- Alibaba Cloud Wanxiang 3.0 all-in-one reference video model
- Text-to-video / first frame / first+last frame / multi-modal reference / file or link reference
- Resolution 480P / 720P / 1080P, duration 2–30 seconds, or
-1for model-chosen length - Supports images, video, audio, documents, and public web pages as references
POST
/
v1
/
videos
/
generations
curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
"resolution": "720P",
"size": "16:9",
"duration": 5
}'
import requests
url = "https://api.apimart.ai/v1/videos/generations"
payload = {
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
"resolution": "720P",
"size": "16:9",
"duration": 5,
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://api.apimart.ai/v1/videos/generations";
const payload = {
model: "wan3.0-video",
prompt: "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
resolution: "720P",
size: "16:9",
duration: 5,
};
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.apimart.ai/v1/videos/generations"
payload := map[string]interface{}{
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop",
"resolution": "720P",
"size": "16:9",
"duration": 5,
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01J9HA7JPQ9A0Z6JZ3V8M9W6PZ"
}
]
}
{
"error": {
"code": 400,
"message": "Invalid request parameters",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed, please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient account balance, please top up and try again",
"type": "payment_required"
}
}
{
"error": {
"code": 429,
"message": "Too many requests, please try again later",
"type": "rate_limit_error"
}
}
curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
"resolution": "720P",
"size": "16:9",
"duration": 5
}'
import requests
url = "https://api.apimart.ai/v1/videos/generations"
payload = {
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
"resolution": "720P",
"size": "16:9",
"duration": 5,
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://api.apimart.ai/v1/videos/generations";
const payload = {
model: "wan3.0-video",
prompt: "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
resolution: "720P",
size: "16:9",
duration: 5,
};
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.apimart.ai/v1/videos/generations"
payload := map[string]interface{}{
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop",
"resolution": "720P",
"size": "16:9",
"duration": 5,
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01J9HA7JPQ9A0Z6JZ3V8M9W6PZ"
}
]
}
{
"error": {
"code": 400,
"message": "Invalid request parameters",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed, please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient account balance, please top up and try again",
"type": "payment_required"
}
}
{
"error": {
"code": 429,
"message": "Too many requests, please try again later",
"type": "rate_limit_error"
}
}
Authorization
string
required
All endpoints require Bearer Token authenticationGet your API Key from the API Key Management Page:
Authorization: Bearer YOUR_API_KEY
Generation Modes
Model name is fixed towan3.0-video. Modes are selected by request fields:
| Mode | Typical inputs |
|---|---|
| Text-to-video | prompt only |
| First-frame video | one item in image_urls (frame family) |
| First + last frame | two items in image_urls, or image_with_roles with first_frame / last_frame |
| Reference video | reference images / videos / audio; prompt may use “图1 / 视频1 / 音频1” style labels |
| File / page reference | file_url or link_url (prompt optional) |
Request Parameters
Basics
string
required
Fixed value:
wan3.0-videoboolean
default:"false"
Whether to run content moderation before submitting the video task.
true: useomni-moderation-latestto review prompts and input imagesfalseor omitted: do not send a moderation request, adding no moderation cost or latency (default)
string
Text description. Required unless media fields are provided (at least one of prompt or media).
- Max 20,000 characters; overflow is truncated automatically (no error)
- In reference mode, use “图N / 视频N / 音频N” to address assets; indices follow order within each media type
string
default:"1080P"
Output resolution (case-insensitive)
480P720P1080P(default, highest price)
Omitting
resolution bills at 1080P. Pass 480P or 720P explicitly when cost matters.string
default:"adaptive"
Aspect ratio.
aspect_ratio is also accepted.adaptive(default)16:9/4:3/1:1/3:4/9:16
integer
default:"5"
Duration in seconds:
2–30: fixed output length (default5)-1: model decides the duration
With reference video input, total input video duration + output duration must be ≤ 30 seconds. When
duration is -1, the model chooses the length, which must still satisfy this constraint.boolean
default:"true"
Whether the output includes an audio track. Default
true. Price is the same with or without audio.integer
Random seed in
[0, 2147483647]boolean
default:"false"
Whether to add a watermark. Default
falsestring
How bare
image_urls are classified:frame— first/last frame familyreference— reference family
Media inputs
string[]
Image URL array. Role assignment follows mutual exclusion rules.Public URL or Base64 (
data:image/png;base64,...).object[]
Images with explicit roles. Each item:
url: image addressrole:first_frame/last_frame/reference_image(common aliases accepted)
string[]
Reference videos, up to 5 clips; each 1–15s, total ≤ 15s
string[]
Reference audio, up to 5 clips; each 1–15s, total ≤ 15s
string
Single reference audio (single-value form of
audio_urls)string
Reference document URL, at most 1. Cannot be combined with
link_url.Formats include docx / doc / xlsx / xls / pptx / ppt / pdf / txt / key / pages / numbers / md, ≤100MB, ≤50 pages.string
Public web page URL, at most 1. Login-free pages only. Cannot be combined with
file_url.Mutual Exclusion of Media Families
Media belongs to one of two families and must not be mixed (validated before submit → 400, no task, no charge):| Family | Members | Meaning |
|---|---|---|
| Frame family | first_frame, last_frame | Strict first / last frame of the video |
| Reference family | reference_image, reference_video, reference_audio, file, link | Model interprets content freely |
How bare image_urls are assigned
- If
generation_typeis set → use it (frame/reference) - Else if the request already has reference-family inputs (
video_urls/audio_urls/audio_url/file_url/link_url) → treat asreference_image - Else → frame family: first item
first_frame, secondlast_frame(same aswan2.7)
image_with_roles when you need explicit control.
Media limits and formats
| Type | Limits |
|---|---|
| First / last frame | ≤ 1 each |
| Reference images | ≤ 10 |
| Reference video | ≤ 5 clips, 1–15s each, total ≤15s; mp4/mov; edge 240–4096 px, aspect ≤8:1, ≤100MB |
| Reference audio | ≤ 5 clips, 1–15s each, total ≤15s; wav/mp3; ≤15MB |
| Images | JPEG/JPG/PNG (no alpha) / BMP / WEBP; edge 240–8000 px, aspect ≤8:1, ≤20MB |
| Documents | ≤100MB, ≤50 pages |
| Web pages | Public, login-free URLs |
Request Examples
Text-to-video
{
"model": "wan3.0-video",
"prompt": "A kitten runs across a moonlit rooftop, neon lights of the city flicker in the distance, cinematic quality, smooth camera move.",
"resolution": "720P",
"size": "16:9",
"duration": 5
}
First-frame video
{
"model": "wan3.0-video",
"prompt": "The person in the frame starts freestyle rapping, camera slowly pushes in",
"image_urls": ["https://example.com/first.png"],
"resolution": "720P",
"duration": 5
}
First + last frame
{
"model": "wan3.0-video",
"prompt": "Smile gradually becomes laughter, background light shifts from cool to warm",
"image_urls": [
"https://example.com/first.png",
"https://example.com/last.jpg"
],
"duration": 5
}
image_with_roles:
{
"model": "wan3.0-video",
"prompt": "Smile gradually becomes laughter",
"image_with_roles": [
{"url": "https://example.com/first.png", "role": "first_frame"},
{"url": "https://example.com/last.jpg", "role": "last_frame"}
],
"duration": 5
}
Multi-modal reference
{
"model": "wan3.0-video",
"prompt": "视频1抱着图1,在图3的椅子上弹奏一支舒缓的乡村民谣,并说道:\"今天的阳光真好。\"",
"generation_type": "reference",
"image_urls": [
"https://example.com/object1.jpg",
"https://example.com/object2.png",
"https://example.com/chair.png"
],
"video_urls": ["https://example.com/role.mp4"],
"resolution": "480P",
"duration": 5
}
Withvideo_urlspresent, bareimage_urlsauto-classify as reference images; settinggeneration_type: "reference"is clearer.
File reference video
prompt may be omitted; generation is driven by the document:
{
"model": "wan3.0-video",
"file_url": "https://example.com/glass.pptx",
"resolution": "480P",
"duration": 10
}
Web page reference video
{
"model": "wan3.0-video",
"prompt": "Turn this article into a short educational video",
"link_url": "https://example.com/article/123",
"duration": 15
}
Billing
Per second × resolution (aligned with official list price). Audio on/off does not change price:| Resolution | Unit price | 5s | 30s |
|---|---|---|---|
| 480P | ¥0.30 / s | ¥1.50 | ¥9.00 |
| 720P | ¥0.60 / s | ¥3.00 | ¥18.00 |
| 1080P | ¥1.20 / s | ¥6.00 | ¥36.00 |
- Default is 1080P (most expensive); pass
480P/720Pwhen cost-sensitive - Billable seconds: for
2–30, use the requestedduration; for-1, use the actual output seconds audio: true/falsedoes not affect price
Limits and Notes
| Item | Notes |
|---|---|
| Duration | Integer 2–30, or -1 (model decides length) |
| With video input | Input video total duration + output duration ≤ 30s |
| Latency | Typically 1–5 minutes; longer for long clips |
| Result URL | Mirrored to the platform CDN after success for long-term access |
| Prompt | ≤20,000 characters; overflow truncated |
Common Errors
All are sync 400 (no task, no charge):| Case | What to do |
|---|---|
| Mixing frame and reference families | Pick one family via generation_type, or set roles with image_with_roles |
Both file_url and link_url | Choose one |
Invalid duration | Only 2–30 or -1 |
| Unsupported resolution (e.g. 4K) | Only 480P / 720P / 1080P |
| More than 10 reference images | Reduce to ≤10 |
Empty prompt and empty media | Provide at least one |
Response
integer
Status code; 200 on success
array
Query resultsVideo generation is async. Poll Get Task Status or
GET /v1/videos/generations/{task_id}.Recommended interval 5–10 seconds; generation typically takes 1–5 minutes. On success, use URLs in result.videos.