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小时后过期,请务必及时保存到自己的存储