通義萬相
curl --request POST \
--url https://api.mixroute.ai/v1/video/generationsimport requests
url = "https://api.mixroute.ai/v1/video/generations"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.mixroute.ai/v1/video/generations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mixroute.ai/v1/video/generations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.mixroute.ai/v1/video/generations"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mixroute.ai/v1/video/generations")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/video/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body視頻系列
通義萬相
萬相 3.0、2.7、2.6 影片生成、參考輸入、編輯參數與非同步任務處理。
通義萬相
curl --request POST \
--url https://api.mixroute.ai/v1/video/generationsimport requests
url = "https://api.mixroute.ai/v1/video/generations"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.mixroute.ai/v1/video/generations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mixroute.ai/v1/video/generations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.mixroute.ai/v1/video/generations"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mixroute.ai/v1/video/generations")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/video/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body萬相使用統一的 MixRoute 影片端點。model 保留在頂層,廠商的 input 與 parameters 物件完整放入 metadata。不同版本使用不同輸入協議,請按完整模型 ID 選擇下方參數。
模型可用性以賬戶的 模型列表 為準,不將未返回的廠商型號或日期快照視為已開通。
提示詞使用 metadata.input.prompt。相容寫法的優先順序依次為 metadata.input.prompt、metadata.prompt、頂層 prompt,前者存在時優先。提示詞與有效媒體至少提供其一,並繼續滿足所選模型自身的必填規則。
原生欄位保持名稱透傳;上游新增欄位可放在原有 input/parameters 位置,由上游校驗型號與場景約束。這不代表每個欄位都適用於所有型號。
I2V 使用 first_clip 續寫時,duration 控制包含源片段的最終總時長,不只是新增秒數。R2V 使用圖1/影片1或 Image 1 / Video 1,圖片與影片分別計數。2.7 不再沿用 2.6 T2V/R2V 的 size 或 shot_type;I2V 輸出比例跟隨源素材,不傳 ratio。
2.6 R2V 按 reference_urls 順序用 character1、character2 等引用主體,不使用 2.7 的圖/影片分別編號。參考素材使用公網 HTTP/HTTPS 或可訪問的 OSS URL。此處列出的 2.6 標準型號不套用其他 Flash 型號的 audio=false 開關;舊版特效模板也不是這八個型號的通用能力。
優先使用公網 URL。OSS 臨時資源和廠商資產 ID 與上游賬戶、地域有關,須可被當前渠道訪問。讀取第三方 CDN 結果地址時,不要附帶 MixRoute Key。
上游完整響應保留在 data.data,可讀取其中的 usage 與 request_id。UNKNOWN 表示上游任務不存在或已過期,不應一概當作生成失敗。建議每 15 秒查詢一次,限流或臨時錯誤時退避。上游任務查詢和結果連結保留期有限,通常為 24 小時,應及時儲存產物。
最終費用以控制台賬單為準。提交可能預扣額度,預扣與任務完成後的結算可能不同;不要將輸入時長、負數或零時長理解為零費用任務。
POST https://api.mixroute.ai/v1/video/generations
支援模型
| 模型 ID | 模式 | 解析度 | 時長(秒) |
|---|---|---|---|
| wan3.0-video | 全能參考影片生成 | 480P / 720P / 1080P | 2-30 / -1 |
| wan2.7-t2v | 文生影片 | 720P / 1080P | 2-15 |
| wan2.7-i2v | 圖生影片 | 720P / 1080P | 2-15 |
| wan2.7-r2v | 參考生影片 | 720P / 1080P | 2-15(無影片)/ 2-10(有影片) |
| wan2.7-videoedit | 影片編輯 | 720P / 1080P | 2-10 |
| wan2.6-t2v | 文生影片 | 720P / 1080P | 2-15 |
| wan2.6-i2v | 圖生影片 | 720P / 1080P | 2-15 |
| wan2.6-r2v | 參考生影片 | 720P / 1080P | 2-10 |
請求包裝
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
model | string | 是 | 完整 MixRoute 模型 ID。 |
metadata | object | 是 | 除 model 之外的廠商請求體容器。 |
metadata.input | object | 是 | 原生 input 物件,提示詞和媒體的必填規則取決於型號。 |
metadata.parameters | object | 否 | 原生生成設定,保留欄位名稱與層級。 |
使用 MixRoute Key 與 Authorization: Bearer 認證,無需阿里 Key、業務空間 ID、地域端點或 X-DashScope-Async 請求頭。不要將 input/parameters 放到頂層,也不要將其內容平鋪到 metadata 下。
Wan 3.0
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
metadata.input.prompt | string | 按模式 | 文本提示詞,最多 20000 字元,超出部分截斷;與 media 至少提供其一。 |
metadata.input.media | object[] | 按模式 | 媒體項陣列,與 prompt 至少提供其一;組合規則見下方。 |
metadata.input.media[].type | string | 按模式 | 每項必填:first_frame、last_frame、reference_image、reference_video、reference_audio、file 或 link。 |
metadata.input.media[].url | string | 按模式 | 每項必填。公網 HTTP/HTTPS URL;影像另支援 Base64 data URI。原生 OSS 資源須可被路由賬戶訪問。 |
metadata.parameters.resolution | string | 否 | 480P、720P 或 1080P;省略時 MixRoute 顯式填入 1080P。 |
metadata.parameters.ratio | string | 否 | adaptive(預設)、16:9、4:3、1:1、3:4 或 9:16;延長影片使用 adaptive。 |
metadata.parameters.duration | integer | 否 | 預設 5 秒。無影片輸入時為 2-30 秒;有影片輸入時,輸入影片總時長與輸出時長之和不超過 30 秒。-1 為智慧時長。 |
metadata.parameters.audio | boolean | 否 | 預設 true;false 輸出無音軌影片。 |
metadata.parameters.seed | integer | 否 | -1 或 0-2147483647;-1 或省略時隨機,不保證輸出完全一致。 |
metadata.parameters.prompt_extend | boolean | 否 | 提示詞智慧改寫,預設 true。 |
metadata.parameters.watermark | boolean | 否 | 新增 AI 水印,預設 false。 |
媒體型別
| type | 數量或用途 |
|---|---|
first_frame / last_frame | 各最多一張,使用首幀或首幀+尾幀,不單獨傳尾幀。 |
reference_image | 最多 10 張參考圖。 |
reference_video | 最多五個影片,每段 1-15 秒,總時長不超過 15 秒。 |
reference_audio | 最多五個音訊,每段 1-15 秒,總時長不超過 15 秒。 |
file | 一個公開文件,不超過 100 MB;分頁格式不超過 50 頁。 |
link | 一個無需登入即可訪問的公開網頁。 |
- 首幀/首尾幀組與 reference_*、file、link 互斥。與萬相 2.7 I2V 不同,3.0 首尾幀模式不能搭配驅動音訊。
- 參考圖片、影片和音訊可相互組合;file 與 link 二選一,但可與 reference_* 組合,仍須滿足各型別數量上限和總計 20 個媒體素材的上限。
- 素材按型別分別計數,在提示詞中用圖1、影片1、音訊1,或 Image 1、Video 1、Audio 1 指代。
- 編輯/延長鬚傳 reference_video 並在提示詞中說明意圖。延長使用 ratio=adaptive;編輯可用 adaptive 與 duration=-1 保留源構圖並自動選擇時長。輸入影片總時長與輸出時長之和仍須不超過 30 秒。
萬相 3.0 不使用 size、negative_prompt、template、img_url、first_frame_url、last_frame_url、audio_url。閘道器會清理舊欄位,並可將 audio_url 轉為 reference_audio 媒體項;新請求直接使用 input.media。
Wan 2.7
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
metadata.input.prompt | string | 按模式 | 最多 5000 字元,超出部分截斷。T2V/R2V 必填;I2V/VideoEdit 提供必需媒體時可省略。 |
metadata.input.negative_prompt | string | 否 | 描述不希望出現的內容,最多 500 字元,超出部分截斷。 |
metadata.input.audio_url | string | 否 | 僅 T2V:驅動音訊 URL,WAV/MP3、2-30 秒、不超過 15 MB;長音訊截斷,短於影片時尾部無聲。 |
metadata.input.media | object[] | 按模式 | I2V、R2V、VideoEdit 必填;各模式使用不同的媒體型別與組合。 |
metadata.input.media[].type | string | 按模式 | 每個媒體項必填,取值須匹配下方的型號規則。 |
metadata.input.media[].url | string | 按模式 | 每個媒體項必填。公網 HTTP/HTTPS URL;影像另支援 data:image/…;base64,…。原生 OSS 引用須可被路由訪問。 |
metadata.input.media[].reference_voice | string | 否 | 僅 R2V 的 reference_image/reference_video:音色參考 URL,WAV/MP3、1-10 秒、不超過 15 MB,優先於參考影片原聲。 |
metadata.parameters.resolution | string | 否 | 720P 或 1080P(預設),注意大小寫。 |
metadata.parameters.ratio | string | 否 | T2V/R2V/VideoEdit:16:9、9:16、1:1、4:3 或 3:4。T2V/R2V 預設 16:9;R2V 有首幀時忽略 ratio。VideoEdit 省略時跟隨源影片。I2V 跟隨輸入影像/影片,不使用此欄位。 |
metadata.parameters.duration | integer | 否 | T2V/I2V 為 2-15 秒,預設 5。R2V 無影片參考時為 2-15 秒,有影片時為 2-10 秒,預設 5。VideoEdit 省略時保留源時長,設定 2-10 時從開頭截斷。 |
metadata.parameters.audio_setting | string | 否 | 僅 VideoEdit:auto(預設)按提示詞決定音訊處理;origin 保留源音訊。 |
metadata.parameters.prompt_extend | boolean | 否 | 提示詞智慧改寫,預設 true。 |
metadata.parameters.watermark | boolean | 否 | 新增 AI 水印,預設 false。 |
metadata.parameters.seed | integer | 否 | 範圍 0-2147483647,省略則隨機;相同種子不保證完全相同的輸出。 |
輸入模式
| 模型 | 媒體規則 |
|---|---|
wan2.7-t2v | prompt 與可選 input.audio_url,不使用 media 陣列。 |
wan2.7-i2v | 僅使用:first_frame;first_frame+driving_audio;first_frame+last_frame;first_frame+last_frame+driving_audio;first_clip;first_clip+last_frame。各 type 最多一次。 |
wan2.7-r2v | reference_image/reference_video 合計 1-5 個,可另配一張 first_frame。reference_voice 位於每個參考項內,不是獨立媒體型別。 |
wan2.7-videoedit | 有且只有一個 type=video 的源影片,可另配最多四張 reference_image。 |
Wan 2.6
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
metadata.input.prompt | string | 按模式 | 最多 1500 字元,超出部分截斷。T2V/R2V 必填;I2V 有輸入影像時可省略。R2V 用 character1、character2 等引用素材。 |
metadata.input.negative_prompt | string | 否 | 反向提示詞,最多 500 字元,超出部分截斷。 |
metadata.input.img_url | string | 按模式 | 僅 I2V,必填:首幀圖片 URL 或影像 Base64 data URI。 |
metadata.input.audio_url | string | 否 | 僅 T2V/I2V:驅動音訊 URL,WAV/MP3、2-30 秒、不超過 15 MB。 |
metadata.input.reference_urls | string[] | 按模式 | 僅 R2V,必填:1-5 個素材 URL,影像最多五張、影片最多三個,合計不超過五個,每個素材包含一個主體。 |
metadata.input.reference_video_urls | string[] | 否 | 已棄用的 R2V 純影片輸入,最多三個影片;優先使用 reference_urls,不混用兩種格式。 |
metadata.parameters.size | string | 否 | 僅 T2V/R2V:使用下方尺寸表中的 寬*高,預設 1920*1080。 |
metadata.parameters.resolution | string | 否 | 僅 I2V:720P 或 1080P(預設),寬高比跟隨首幀影像。 |
metadata.parameters.duration | integer | 否 | T2V/I2V 為 2-15 秒,R2V 為 2-10 秒,預設 5。 |
metadata.parameters.prompt_extend | boolean | 否 | 僅 T2V/I2V:提示詞智慧改寫,預設 true;不是 R2V 參數。 |
metadata.parameters.shot_type | string | 否 | single(預設)或 multi。T2V/I2V 須同時開啟 prompt_extend 才生效;R2V 直接使用此欄位。優先順序高於提示詞中的鏡頭描述。 |
metadata.parameters.watermark | boolean | 否 | 新增 AI 水印,預設 false。 |
metadata.parameters.seed | integer | 否 | 範圍 0-2147483647,省略則隨機;相同種子不保證完全相同的輸出。 |
T2V / R2V 尺寸
| 檔位 | size 取值 |
|---|---|
| 720P | 1280*720, 720*1280, 960*960, 1088*832, 832*1088 |
| 1080P | 1920*1080, 1080*1920, 1440*1440, 1632*1248, 1248*1632 |
媒體限制
| 輸入 | 限制 |
|---|---|
| 影像 | JPEG/JPG、無透明通道 PNG、BMP、WebP;寬高各 240-8000 px,不超過 20 MB。3.0/2.7 另要求長短邊比不超過 8:1。 |
| 3.0 參考影片 | MP4/MOV,每段 1-15 秒、合計不超過 15 秒;至少 16 fps;寬高各 240-4096 px;長短邊比不超過 8:1;單個不超過 100 MB。 |
| 2.7 影片 | MP4/MOV;寬高各 240-4096 px,長短邊比不超過 8:1,不超過 100 MB。first_clip/VideoEdit 源影片為 2-10 秒,R2V 參考影片為 1-30 秒。 |
| 2.6 R2V 影片 | reference_urls 支援 MP4/MOV、1-30 秒、不超過 100 MB;已棄用 reference_video_urls 格式的時長為 2-30 秒。 |
| 音訊 | WAV/MP3,單個不超過 15 MB。3.0 參考音訊每段 1-15 秒、合計不超過 15;2.7 reference_voice 為 1-10 秒;T2V 驅動音訊與 I2V driving_audio 為 2-30 秒。 |
| 3.0 檔案 | docx, doc, xlsx, xls, pptx, ppt, pdf, txt, key, pages, numbers, md; 不超過 100 MB;PDF/Word/PowerPoint/Keynote/Pages 文件不超過 50 頁。 |
請求示例
設定 MIXROUTE_API_KEY,並將 example.com 媒體地址替換為可訪問的源素材。每次 POST 會建立獨立任務,提交超時後不要自動重複提交。Wan 3.0 Video
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan3.0-video",
"metadata": {
"input": {
"prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting."
},
"parameters": {
"resolution": "480P",
"ratio": "16:9",
"duration": 2,
"audio": false,
"prompt_extend": false,
"watermark": false
}
}
}'
Wan 2.7 T2V
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.7-t2v",
"metadata": {
"input": {
"prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting."
},
"parameters": {
"resolution": "720P",
"ratio": "9:16",
"duration": 2,
"prompt_extend": false,
"watermark": false
}
}
}'
Wan 2.7 I2V
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.7-i2v",
"metadata": {
"input": {
"prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting.",
"media": [
{
"type": "first_frame",
"url": "https://example.com/reference.png"
}
]
},
"parameters": {
"resolution": "720P",
"duration": 2,
"prompt_extend": false,
"watermark": false
}
}
}'
Wan 2.7 R2V
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.7-r2v",
"metadata": {
"input": {
"prompt": "Image 1 slowly rotates on a white tabletop. Static camera, soft studio lighting.",
"media": [
{
"type": "reference_image",
"url": "https://example.com/reference.png"
}
]
},
"parameters": {
"resolution": "720P",
"ratio": "1:1",
"duration": 2,
"watermark": false
}
}
}'
Wan 2.7 VideoEdit
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.7-videoedit",
"metadata": {
"input": {
"prompt": "Change the mug color to blue while preserving the original motion and white tabletop.",
"media": [
{
"type": "video",
"url": "https://example.com/source.mp4"
}
]
},
"parameters": {
"resolution": "720P",
"duration": 2,
"watermark": false
}
}
}'
Wan 2.6 T2V
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.6-t2v",
"metadata": {
"input": {
"prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting."
},
"parameters": {
"size": "1280*720",
"duration": 2,
"prompt_extend": false,
"watermark": false
}
}
}'
Wan 2.6 I2V
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.6-i2v",
"metadata": {
"input": {
"prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting.",
"img_url": "https://example.com/reference.png"
},
"parameters": {
"resolution": "720P",
"duration": 2,
"prompt_extend": false,
"watermark": false
}
}
}'
Wan 2.6 R2V
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.6-r2v",
"metadata": {
"input": {
"prompt": "character1 slowly rotates on a white tabletop. Static camera, soft studio lighting.",
"reference_urls": [
"https://example.com/reference.png"
]
},
"parameters": {
"size": "1280*720",
"duration": 2,
"watermark": false
}
}
}'
首尾幀
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan2.7-i2v",
"metadata": {
"input": {
"prompt": "A closed gift box slowly opens, revealing a red ceramic mug.",
"media": [
{
"type": "first_frame",
"url": "https://example.com/first.png"
},
{
"type": "last_frame",
"url": "https://example.com/last.png"
}
]
},
"parameters": {
"resolution": "720P",
"duration": 5
}
}
}'
檔案輸入,不傳提示詞
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "wan3.0-video",
"metadata": {
"input": {
"media": [
{
"type": "file",
"url": "https://example.com/product.pptx"
}
]
},
"parameters": {
"resolution": "480P",
"duration": 5
}
}
}'
響應與輪詢
提交返回 MixRoute task_id(以及 id 別名),不是上游任務 ID。{
"id": "TASK_ID",
"task_id": "TASK_ID",
"object": "video",
"model": "wan3.0-video",
"status": "queued"
}
GET https://api.mixroute.ai/v1/video/generations/{task_id}
| 閘道器狀態 | 上游狀態 | 處理 |
|---|---|---|
NOT_START / QUEUED | PENDING | 等待並繼續查詢。 |
IN_PROGRESS | RUNNING | 繼續輪詢。 |
SUCCESS | SUCCEEDED | 讀取 data.result_url。 |
FAILURE | FAILED / CANCELED / UNKNOWN | 停止,檢查 data.fail_reason 與上游響應。 |
{
"code": "success",
"message": "",
"data": {
"task_id": "TASK_ID",
"status": "SUCCESS",
"progress": "100%",
"result_url": "https://example.com/generated.mp4",
"fail_reason": "",
"data": {
"request_id": "UPSTREAM_REQUEST_ID",
"output": {
"task_id": "UPSTREAM_TASK_ID",
"task_status": "SUCCEEDED",
"video_url": "https://example.com/generated.mp4"
},
"usage": {
"output_video_duration": 2,
"SR": 480,
"video_count": 1
}
}
}
}
只在 SUCCESS 後讀取 result_url。失敗時該欄位可能填入失敗原因,不一定是 URL。外層 code=“success” 僅代表查詢成功,不代表影片生成成功。
Python 完整流程
import os
import time
from urllib.parse import quote, urlparse
import requests
BASE_URL = "https://api.mixroute.ai"
def create_video(session, payload):
response = session.post(BASE_URL + "/v1/video/generations", json=payload, timeout=120)
response.raise_for_status()
result = response.json()
task_id = result.get("task_id") or result.get("id")
if not task_id:
raise RuntimeError(result.get("message") or result)
return task_id
def wait_for_video(session, task_id, timeout_seconds=1200):
url = BASE_URL + "/v1/video/generations/" + quote(task_id, safe="")
deadline = time.monotonic() + timeout_seconds
delay = 15
while time.monotonic() < deadline:
remaining = deadline - time.monotonic()
if remaining <= 0:
break
try:
response = session.get(url, timeout=min(30, remaining))
except (requests.Timeout, requests.ConnectionError):
delay = min(delay * 2, 60)
else:
if response.status_code in (429, 500, 502, 503, 504):
delay = min(delay * 2, 60)
else:
response.raise_for_status()
result = response.json()
if result.get("code") not in (None, 0, 200, "0", "200", "success"):
raise RuntimeError(result.get("message") or result)
task = result.get("data") or {}
status = str(task.get("status", "")).upper()
if status == "SUCCESS":
video_url = task.get("result_url", "")
parsed = urlparse(video_url)
if parsed.scheme not in ("http", "https") or not parsed.netloc:
raise RuntimeError("Successful task has no valid video URL")
return task
if status in {"FAILURE", "FAILED", "EXPIRED", "CANCELED", "CANCELLED"}:
raise RuntimeError(task.get("fail_reason") or task)
if status not in {"QUEUED", "NOT_START", "PENDING", "IN_PROGRESS", "RUNNING"}:
raise RuntimeError("Unknown task status: " + status)
delay = 15
remaining = deadline - time.monotonic()
if remaining <= 0:
break
time.sleep(min(delay, remaining))
raise TimeoutError("Video task is still pending; keep its task ID and query it later")
if __name__ == "__main__":
payload = {
"model": "wan3.0-video",
"metadata": {
"input": {"prompt": "A red ceramic mug slowly rotates on a white tabletop."},
"parameters": {"resolution": "480P", "ratio": "16:9", "duration": 2, "audio": False},
},
}
with requests.Session() as session:
session.headers["Authorization"] = "Bearer " + os.environ["MIXROUTE_API_KEY"]
task_id = create_video(session, payload)
print("task_id:", task_id, flush=True)
task = wait_for_video(session, task_id)
print(task["result_url"])
print(task.get("data", {}).get("usage", {}))