curl --request GET \
--url 'https://toapis.com/v1/videos/generations/task_01K9S419324DREZFBWNSVXYR6H' \
--header 'Authorization: Bearer <token>'
import requests
import time
API_BASE = 'https://toapis.com'
API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx'
headers = {
'Authorization': f'Bearer {API_KEY}'
}
def get_video_status(task_id):
response = requests.get(f'{API_BASE}/v1/videos/generations/{task_id}', headers=headers)
return response.json()
def wait_for_video(task_id, max_attempts=60, interval=10):
for _ in range(max_attempts):
result = get_video_status(task_id)
status = result.get('status')
progress = result.get('progress', 0)
print(f"狀態: {status}, 進度: {progress}%")
if status == 'completed':
return result
elif status == 'failed':
raise Exception(f"任務失敗: {result}")
time.sleep(interval)
raise Exception("任務超時")
# 使用示例
task_id = "video_7497f4d5-3a88-44c7-923a-967fa7d941a0"
result = wait_for_video(task_id)
print(f"視頻URL: {result['result']['data'][0]['url']}")
const API_BASE = 'https://toapis.com';
const API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx';
async function getVideoStatus(taskId) {
const response = await fetch(`${API_BASE}/v1/videos/generations/${taskId}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
return response.json();
}
async function waitForVideo(taskId, maxAttempts = 60, interval = 10000) {
for (let i = 0; i < maxAttempts; i++) {
const result = await getVideoStatus(taskId);
const status = result.status;
const progress = result.progress || 0;
console.log(`狀態: ${status}, 進度: ${progress}%`);
if (status === 'completed') {
return result;
} else if (status === 'failed') {
throw new Error(`任務失敗: ${JSON.stringify(result)}`);
}
await new Promise(r => setTimeout(r, interval));
}
throw new Error('任務超時');
}
// 使用示例
const taskId = 'video_7497f4d5-3a88-44c7-923a-967fa7d941a0';
waitForVideo(taskId).then(result => {
console.log('視頻URL:', result.result.data[0].url);
console.log('格式:', result.result.data[0].format);
});
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)
func getVideoStatus(taskId string) (map[string]interface{}, error) {
url := fmt.Sprintf("https://toapis.com/v1/videos/generations/%s", taskId)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer <token>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
return result, nil
}
func main() {
taskId := "video_7497f4d5-3a88-44c7-923a-967fa7d941a0"
for i := 0; i < 60; i++ {
result, _ := getVideoStatus(taskId)
status := result["status"].(string)
progress := int(result["progress"].(float64))
fmt.Printf("狀態: %s, 進度: %d%%\n", status, progress)
if status == "completed" {
fmt.Println("視頻生成完成!")
resultData := result["result"].(map[string]interface{})
dataArray := resultData["data"].([]interface{})
videoData := dataArray[0].(map[string]interface{})
fmt.Println("視頻URL:", videoData["url"])
break
}
time.Sleep(10 * time.Second)
}
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1768380222
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "in_progress",
"progress": 65,
"created_at": 1768380222
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"client_business_id": "order_20260428_001",
"object": "generation.task",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1768380222,
"finished_at": 1768380514,
"completed_at": 1768380514,
"expires_at": 1768466914,
"result": {
"type": "video",
"data": [
{
"url": "https://files.toapis.com/sora/7712af45-ca35-4a15-b800-f20ea623665b.mp4",
"format": "mp4"
}
]
},
"billing": {
"status": "settled",
"credits": "100",
"cost_usd": "0.5"
}
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "failed",
"progress": 0,
"created_at": 1768380222,
"error": {
"code": "generation_failed",
"message": "生成失敗: 內容違反了內容政策"
}
}
{
"error": {
"code": 404,
"message": "任務不存在",
"type": "not_found_error"
}
}
{
"error": {
"code": 401,
"message": "身份驗證失敗,請檢查您的API密鑰",
"type": "authentication_error"
}
}
{
"id": "task_seedance_example",
"object": "generation.task",
"model": "seedance-2-global",
"client_business_id": "order_123",
"status": "completed",
"progress": 100,
"created_at": 1792400000,
"updated_at": 1792400061,
"finished_at": 1792400060,
"completed_at": 1792400060,
"expires_at": 1792486460,
"result": {
"type": "video",
"data": [
{
"url": "https://cdn.example/result.mp4",
"fallback_url": "https://files.toapis.com/videos/task_seedance_example/result.mp4",
"format": "mp4",
"last_frame_url": "https://cdn.example/last-frame.jpg",
"fallback_last_frame_url": "https://files.toapis.com/videos/task_seedance_example/last-frame.jpg"
}
]
},
"usage": {
"charge_type": "per_token",
"billed_tokens": 87300,
"completion_tokens": 87300,
"total_tokens": 87300
},
"billing": {
"status": "settled",
"credits": "87.3",
"cost_usd": "0.4365"
},
"generation": {
"duration": 5,
"resolution": "720p",
"ratio": "16:9",
"generate_audio": true,
"usage": {
"completion_tokens": 87300,
"total_tokens": 87300
}
}
}
獲取視頻任務狀態
獲取視頻任務狀態
查詢視頻生成任務的狀態和結果
GET
/
v1
/
videos
/
generations
/
{task_id}
curl --request GET \
--url 'https://toapis.com/v1/videos/generations/task_01K9S419324DREZFBWNSVXYR6H' \
--header 'Authorization: Bearer <token>'
import requests
import time
API_BASE = 'https://toapis.com'
API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx'
headers = {
'Authorization': f'Bearer {API_KEY}'
}
def get_video_status(task_id):
response = requests.get(f'{API_BASE}/v1/videos/generations/{task_id}', headers=headers)
return response.json()
def wait_for_video(task_id, max_attempts=60, interval=10):
for _ in range(max_attempts):
result = get_video_status(task_id)
status = result.get('status')
progress = result.get('progress', 0)
print(f"狀態: {status}, 進度: {progress}%")
if status == 'completed':
return result
elif status == 'failed':
raise Exception(f"任務失敗: {result}")
time.sleep(interval)
raise Exception("任務超時")
# 使用示例
task_id = "video_7497f4d5-3a88-44c7-923a-967fa7d941a0"
result = wait_for_video(task_id)
print(f"視頻URL: {result['result']['data'][0]['url']}")
const API_BASE = 'https://toapis.com';
const API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx';
async function getVideoStatus(taskId) {
const response = await fetch(`${API_BASE}/v1/videos/generations/${taskId}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
return response.json();
}
async function waitForVideo(taskId, maxAttempts = 60, interval = 10000) {
for (let i = 0; i < maxAttempts; i++) {
const result = await getVideoStatus(taskId);
const status = result.status;
const progress = result.progress || 0;
console.log(`狀態: ${status}, 進度: ${progress}%`);
if (status === 'completed') {
return result;
} else if (status === 'failed') {
throw new Error(`任務失敗: ${JSON.stringify(result)}`);
}
await new Promise(r => setTimeout(r, interval));
}
throw new Error('任務超時');
}
// 使用示例
const taskId = 'video_7497f4d5-3a88-44c7-923a-967fa7d941a0';
waitForVideo(taskId).then(result => {
console.log('視頻URL:', result.result.data[0].url);
console.log('格式:', result.result.data[0].format);
});
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)
func getVideoStatus(taskId string) (map[string]interface{}, error) {
url := fmt.Sprintf("https://toapis.com/v1/videos/generations/%s", taskId)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer <token>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
return result, nil
}
func main() {
taskId := "video_7497f4d5-3a88-44c7-923a-967fa7d941a0"
for i := 0; i < 60; i++ {
result, _ := getVideoStatus(taskId)
status := result["status"].(string)
progress := int(result["progress"].(float64))
fmt.Printf("狀態: %s, 進度: %d%%\n", status, progress)
if status == "completed" {
fmt.Println("視頻生成完成!")
resultData := result["result"].(map[string]interface{})
dataArray := resultData["data"].([]interface{})
videoData := dataArray[0].(map[string]interface{})
fmt.Println("視頻URL:", videoData["url"])
break
}
time.Sleep(10 * time.Second)
}
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1768380222
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "in_progress",
"progress": 65,
"created_at": 1768380222
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"client_business_id": "order_20260428_001",
"object": "generation.task",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1768380222,
"finished_at": 1768380514,
"completed_at": 1768380514,
"expires_at": 1768466914,
"result": {
"type": "video",
"data": [
{
"url": "https://files.toapis.com/sora/7712af45-ca35-4a15-b800-f20ea623665b.mp4",
"format": "mp4"
}
]
},
"billing": {
"status": "settled",
"credits": "100",
"cost_usd": "0.5"
}
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "failed",
"progress": 0,
"created_at": 1768380222,
"error": {
"code": "generation_failed",
"message": "生成失敗: 內容違反了內容政策"
}
}
{
"error": {
"code": 404,
"message": "任務不存在",
"type": "not_found_error"
}
}
{
"error": {
"code": 401,
"message": "身份驗證失敗,請檢查您的API密鑰",
"type": "authentication_error"
}
}
{
"id": "task_seedance_example",
"object": "generation.task",
"model": "seedance-2-global",
"client_business_id": "order_123",
"status": "completed",
"progress": 100,
"created_at": 1792400000,
"updated_at": 1792400061,
"finished_at": 1792400060,
"completed_at": 1792400060,
"expires_at": 1792486460,
"result": {
"type": "video",
"data": [
{
"url": "https://cdn.example/result.mp4",
"fallback_url": "https://files.toapis.com/videos/task_seedance_example/result.mp4",
"format": "mp4",
"last_frame_url": "https://cdn.example/last-frame.jpg",
"fallback_last_frame_url": "https://files.toapis.com/videos/task_seedance_example/last-frame.jpg"
}
]
},
"usage": {
"charge_type": "per_token",
"billed_tokens": 87300,
"completion_tokens": 87300,
"total_tokens": 87300
},
"billing": {
"status": "settled",
"credits": "87.3",
"cost_usd": "0.4365"
},
"generation": {
"duration": 5,
"resolution": "720p",
"ratio": "16:9",
"generate_audio": true,
"usage": {
"completion_tokens": 87300,
"total_tokens": 87300
}
}
}
中國大陸用戶請注意: 中國大陸用戶請使用
https://toapis.cn 作為接口地址(Base URL)。文檔示例中的 https://toapis.com 請替換為 https://toapis.cn。- 查詢異步視頻生成任務的執行狀態和結果
- 實時狀態更新和進度跟蹤
- 任務完成時獲取生成的視頻
- 支持多語言返回(zh/en/ko/ja)
Seedance 影片任務需要素材審核時也透過本接口查詢.
queued 可能包含素材準備與審核等待, 返回任務不表示影片已開始生成. 預設每輪準備期限為 20 分鐘, 後續影片生成時間另計; 失敗原因請查看 error.message.GET /v1/tasks/{task_id} 查詢, usage 和 billing 採用相同口徑. 本頁描述的是頁首生成任務查詢路徑的回應.
以下範例用於展示欄位, 不代表模型目前的價格或固定計費方式. 實際欄位與金額以本次任務回傳為準.
Seedance 原始位址與備用位址
啟用原始位址交付的 Seedance 任務,result.data[].url 保留上游原始影片 URL. 用戶端應優先使用 url, 只有該位址無法存取時才切換到同一結果項目的 fallback_url. 平台不會根據用戶端所在地區自動切換位址.
備用欄位皆為可選: 只有副本準備成功時才回傳. 未啟用原始位址交付, 備用副本不可用或歷史任務沒有副本時, 欄位可能省略; 省略不表示生成失敗. 尾幀同樣優先使用 last_frame_url, 無法存取時再使用 fallback_last_frame_url. 備用位址不會延長原始 URL 的有效期, 需要長期保存時請及時下載.
創建任務時傳入業務 ID
創建視頻任務時,可以在請求體頂層傳入client_business_id。該字段用於保存您系統內的訂單號、流水號或業務任務 ID,方便後續按業務 ID 查詢生成結果。
{
"model": "sora-2",
"client_business_id": "order_20260428_002",
"prompt": "海浪拍打着海岸",
"duration": 15,
"aspect_ratio": "16:9"
}
metadata.client_business_id 中,但推薦使用頂層字段。
Authorizations
string
必填
所有接口均需要使用 Bearer Token 進行認證獲取 API Key:訪問 API Key 管理頁面 獲取您的 API Key使用時在請求頭中添加:
Authorization: Bearer YOUR_API_KEY
Path Parameters
string
必填
視頻生成 API 返回的任務 ID。也可以傳創建任務時提交的
client_business_id,用於按客戶側業務 ID 查詢任務狀態和結果。如果創建視頻任務時傳入
client_business_id,可直接使用同一個狀態查詢接口:
GET /v1/videos/generations/{client_business_id}。業務 ID 會限定在當前 API Key 所屬用戶下查詢。curl --request GET \
--url 'https://toapis.com/v1/videos/generations/task_01K9S419324DREZFBWNSVXYR6H' \
--header 'Authorization: Bearer <token>'
import requests
import time
API_BASE = 'https://toapis.com'
API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx'
headers = {
'Authorization': f'Bearer {API_KEY}'
}
def get_video_status(task_id):
response = requests.get(f'{API_BASE}/v1/videos/generations/{task_id}', headers=headers)
return response.json()
def wait_for_video(task_id, max_attempts=60, interval=10):
for _ in range(max_attempts):
result = get_video_status(task_id)
status = result.get('status')
progress = result.get('progress', 0)
print(f"狀態: {status}, 進度: {progress}%")
if status == 'completed':
return result
elif status == 'failed':
raise Exception(f"任務失敗: {result}")
time.sleep(interval)
raise Exception("任務超時")
# 使用示例
task_id = "video_7497f4d5-3a88-44c7-923a-967fa7d941a0"
result = wait_for_video(task_id)
print(f"視頻URL: {result['result']['data'][0]['url']}")
const API_BASE = 'https://toapis.com';
const API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx';
async function getVideoStatus(taskId) {
const response = await fetch(`${API_BASE}/v1/videos/generations/${taskId}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
return response.json();
}
async function waitForVideo(taskId, maxAttempts = 60, interval = 10000) {
for (let i = 0; i < maxAttempts; i++) {
const result = await getVideoStatus(taskId);
const status = result.status;
const progress = result.progress || 0;
console.log(`狀態: ${status}, 進度: ${progress}%`);
if (status === 'completed') {
return result;
} else if (status === 'failed') {
throw new Error(`任務失敗: ${JSON.stringify(result)}`);
}
await new Promise(r => setTimeout(r, interval));
}
throw new Error('任務超時');
}
// 使用示例
const taskId = 'video_7497f4d5-3a88-44c7-923a-967fa7d941a0';
waitForVideo(taskId).then(result => {
console.log('視頻URL:', result.result.data[0].url);
console.log('格式:', result.result.data[0].format);
});
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)
func getVideoStatus(taskId string) (map[string]interface{}, error) {
url := fmt.Sprintf("https://toapis.com/v1/videos/generations/%s", taskId)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer <token>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
return result, nil
}
func main() {
taskId := "video_7497f4d5-3a88-44c7-923a-967fa7d941a0"
for i := 0; i < 60; i++ {
result, _ := getVideoStatus(taskId)
status := result["status"].(string)
progress := int(result["progress"].(float64))
fmt.Printf("狀態: %s, 進度: %d%%\n", status, progress)
if status == "completed" {
fmt.Println("視頻生成完成!")
resultData := result["result"].(map[string]interface{})
dataArray := resultData["data"].([]interface{})
videoData := dataArray[0].(map[string]interface{})
fmt.Println("視頻URL:", videoData["url"])
break
}
time.Sleep(10 * time.Second)
}
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1768380222
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "in_progress",
"progress": 65,
"created_at": 1768380222
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"client_business_id": "order_20260428_001",
"object": "generation.task",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1768380222,
"finished_at": 1768380514,
"completed_at": 1768380514,
"expires_at": 1768466914,
"result": {
"type": "video",
"data": [
{
"url": "https://files.toapis.com/sora/7712af45-ca35-4a15-b800-f20ea623665b.mp4",
"format": "mp4"
}
]
},
"billing": {
"status": "settled",
"credits": "100",
"cost_usd": "0.5"
}
}
{
"id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
"object": "generation.task",
"model": "sora-2",
"status": "failed",
"progress": 0,
"created_at": 1768380222,
"error": {
"code": "generation_failed",
"message": "生成失敗: 內容違反了內容政策"
}
}
{
"error": {
"code": 404,
"message": "任務不存在",
"type": "not_found_error"
}
}
{
"error": {
"code": 401,
"message": "身份驗證失敗,請檢查您的API密鑰",
"type": "authentication_error"
}
}
{
"id": "task_seedance_example",
"object": "generation.task",
"model": "seedance-2-global",
"client_business_id": "order_123",
"status": "completed",
"progress": 100,
"created_at": 1792400000,
"updated_at": 1792400061,
"finished_at": 1792400060,
"completed_at": 1792400060,
"expires_at": 1792486460,
"result": {
"type": "video",
"data": [
{
"url": "https://cdn.example/result.mp4",
"fallback_url": "https://files.toapis.com/videos/task_seedance_example/result.mp4",
"format": "mp4",
"last_frame_url": "https://cdn.example/last-frame.jpg",
"fallback_last_frame_url": "https://files.toapis.com/videos/task_seedance_example/last-frame.jpg"
}
]
},
"usage": {
"charge_type": "per_token",
"billed_tokens": 87300,
"completion_tokens": 87300,
"total_tokens": 87300
},
"billing": {
"status": "settled",
"credits": "87.3",
"cost_usd": "0.4365"
},
"generation": {
"duration": 5,
"resolution": "720p",
"ratio": "16:9",
"generate_audio": true,
"usage": {
"completion_tokens": 87300,
"total_tokens": 87300
}
}
}
Response
string
任務唯一標識符
string
客戶側業務 ID。僅當創建任務時傳入
client_business_id 時返回。string
對象類型,固定爲
generation.taskstring
使用的視頻生成模型
string
任務狀態
queued- 排隊等待處理in_progress- 處理中completed- 成功完成failed- 失敗
integer
任務進度百分比(0-100)
integer
可選的平台任務更新時間, Unix 時間戳. 目前用於 Seedance Global;
generation.updated_at 是上游更新時間.integer
任務創建時間(Unix 時間戳)
integer
任務結束時間, Unix 時間戳. 本頁查詢路徑在任務成功或失敗且已儲存結束時間時回傳.
integer
任務完成時間(Unix 時間戳,僅完成時返回)
integer
視頻 URL 過期時間(Unix 時間戳,僅完成時返回)
object
任務結果(僅成功時返回)
object
可選的 Seedance 生成中繼資料. 僅回傳已儲存且可公開的欄位, 不補預設值. 這些參數描述生成任務, 不取代頂層
usage 的計費量.| 欄位 | 型別 | 說明 |
|---|---|---|
created_at, updated_at | number | 上游任務建立和更新時間, Unix 時間戳; 與平台頂層時間區分 |
seed | number | 隨機種子 |
resolution | string | 解析度 |
ratio | string | 長寬比 |
duration | number | 生成時長, 單位為秒 |
framespersecond | number | 影格率, 單位為影格/秒 |
service_tier | string | 服務等級 |
execution_expires_after | number | 執行有效期, 單位為秒 |
generate_audio | boolean | 是否生成音訊 |
draft | boolean | 是否為草稿 |
priority | number | 排程優先順序 |
output_format | string | 輸出格式 |
generation.usage 是保留相容性的舊欄位, 可包含 completion_tokens 和 total_tokens. 它可能缺少或與最終計費量不同, 不與頂層 usage 相加; 讀取計費量時使用頂層 usage.object
可選的計費量, 影片 token 明細及工具次數. 各欄位的單位及省略規則見任務用量欄位.
| 欄位 | 類型 | 取值 |
|---|---|---|
charge_type | string | 計費方式: per_request 按次, per_second 按秒, per_token 按 token |
requests | integer | 計費次數, per_request 時回傳. Midjourney 影片的有效 batch_size 計入次數 |
billed_tokens | integer | 計價 token 數, per_token 時回傳 |
output_seconds | integer | 參與計費的輸出影片時長, 整數秒, per_second 時回傳 |
input_seconds | integer | 參與計費的輸入影片時長, 整數秒, 為零時省略 |
input_images | integer | 扣除免費額度後參與計費的輸入圖片數, 為零時省略 |
input_tokens, output_tokens, prompt_tokens, completion_tokens, total_tokens | integer | 影片模型回報的 token 數, 依供應商實際提供情況回傳; 按 token 結算後可補齊 total_tokens |
tool_usage | object | 工具次數: web_search, image_search, grounding_queries, 依實際發生回傳 |
charge_type 到 input_images 是計費量, 只與 billing.status=settled 同時回傳. 固定價影片按提交時確認的數量回傳, 按實際時長或 token 結算的影片按最終結算數量回傳. 未回傳的欄位直接省略, 不補零.object
選填的平台計費狀態和已確認費用. 計費狀態獨立於任務生成狀態,
任務 Webhook 的
completed 不保證已經結算. 缺少此物件不代表任務免費. 詳見價格與實際費用.顯示 屬性
顯示 屬性
data.billing 使用相同的確認條件和取值.object
任務狀態說明
| 狀態 | 說明 | 是否終態 | 建議操作 |
|---|---|---|---|
queued | 任務排隊等待處理 | ❌ | 等待 5-10 秒後重試查詢 |
in_progress | 任務正在處理中 | ❌ | 等待 10-15 秒後重試查詢 |
completed | 任務成功完成 | ✅ | 從 result.data[0].url 獲取視頻 |
failed | 任務處理失敗 | ✅ | 檢查 error 信息 |
輪詢策略建議
初始等待: 5 秒
輪詢間隔: 10 秒
最大等待: 600 秒(10分鐘)
典型耗時: 1-5 分鐘
Python 輪詢示例
import time
import random
import requests
def poll_video_task(task_id, api_key, max_wait=600):
"""輪詢視頻生成任務直到完成或超時"""
start_time = time.time()
interval = 10 # 10秒間隔
# 首次等待5秒
time.sleep(5)
while time.time() - start_time < max_wait:
response = requests.get(
f'https://toapis.com/v1/videos/generations/{task_id}',
headers={'Authorization': f'Bearer {api_key}'}
)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', interval))
time.sleep(retry_after + random.uniform(0, 1))
interval = min(interval * 2, 120)
continue
response.raise_for_status()
data = response.json()
print(f"狀態: {data['status']}, 進度: {data.get('progress', 0)}%")
if data['status'] == 'completed':
return {
'url': data['result']['data'][0]['url'],
'format': data['result']['data'][0].get('format'),
'expires_at': data.get('expires_at')
}
elif data['status'] == 'failed':
raise Exception(f"生成失敗: {data['error']['message']}")
time.sleep(interval + random.uniform(0, 1))
raise TimeoutError("任務超時")
視頻資源有效期
生成的視頻 URL 有效期爲 24 小時
- 請在有效期內下載保存視頻
expires_at字段標識視頻過期時間(Unix 時間戳)- 視頻過期後無法訪問,如需重新獲取,需要重新提交生成任務
- 縮略圖與視頻同步過期
錯誤碼與失敗原因
請求錯誤與任務失敗的差異, 具體原因及處理方式, 請見錯誤碼速查. 查詢成功仍需檢查任務狀態, HTTP 狀態不是業務錯誤碼.性能建議
視頻生成耗時較長,建議:
- 使用 ToAPIs 統一任務 Webhook:以 Webhook 為主,輪詢為後備
- 合理設置輪詢間隔:至少5~10秒並加入抖動;429 時讀取
Retry-After後指數退避 - 設置超時時間:長視頻生成可能需要5-10分鐘,請設置合理的超時
- 及時下載保存:視頻24小時後過期,請務必及時保存到自己的存儲