ToAPIsToAPIs
获取视频任务状态

获取视频任务状态

查询视频生成任务的状态和结果

GET
/v1/videos/generations/%7Btask_id%7D

国内用户请注意: 中国大陆用户请使用 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

Authorizationstring请求头必填

所有接口均需要使用 Bearer Token 进行认证

获取 API Key:

访问 API Key 管理页面 获取您的 API Key

使用时在请求头中添加:

Authorization: Bearer YOUR_API_KEY

Path Parameters

task_idstring路径必填

视频生成 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

idstring

任务唯一标识符

client_business_idstring

客户侧业务 ID。仅当创建任务时传入 client_business_id 时返回。

objectstring

对象类型,固定为 generation.task

modelstring

使用的视频生成模型

statusstring

任务状态

  • queued - 排队等待处理
  • in_progress - 处理中
  • completed - 成功完成
  • failed - 失败
progressinteger

任务进度百分比(0-100)

updated_atinteger

可选的平台任务更新时间, Unix 时间戳. 当前用于 Seedance Global; generation.updated_at 是上游更新时间.

created_atinteger

任务创建时间(Unix 时间戳)

finished_atinteger

任务结束时间, Unix 时间戳. 本页查询路径在任务成功或失败且已保存结束时间时返回.

completed_atinteger

任务完成时间(Unix 时间戳,仅完成时返回)

expires_atinteger

视频 URL 过期时间(Unix 时间戳,仅完成时返回)

resultobject

任务结果(仅成功时返回)

属性
typestring

结果类型,固定为 video

dataarray

视频数据数组

数组元素
urlstring

视频主地址. 启用原始地址交付的 Seedance 任务保留上游原始 URL, 优先使用该地址.

fallback_urlstring

可选的视频备用 URL. 仅在副本可用时返回; 主地址无法访问时才使用, 不替换 url.

formatstring

视频格式(如 mp4)

last_frame_urlstring

生成视频的尾帧图像 URL。仅当创建任务时设置 return_last_frame: true 且模型返回尾帧时出现。

fallback_last_frame_urlstring

可选的尾帧备用 URL. 尾帧副本可用时返回; 仅在 last_frame_url 无法访问时使用.

generationobject

可选的 Seedance 生成元数据. 仅返回已保存且可公开的字段, 不补默认值. 这些参数描述生成任务, 不替代顶层 usage 的计费量.

字段类型说明
created_at, updated_atnumber上游任务创建和更新时间, Unix 时间戳; 与平台顶层时间区分
seednumber随机种子
resolutionstring分辨率
ratiostring宽高比
durationnumber生成时长, 单位为秒
framespersecondnumber帧率, 单位为帧/秒
service_tierstring服务档位
execution_expires_afternumber执行有效期, 单位为秒
generate_audioboolean是否生成音频
draftboolean是否为草稿
prioritynumber调度优先级
output_formatstring输出格式

generation.usage 是保留兼容的旧字段, 可包含 completion_tokens 和 total_tokens. 它可能缺失或与最终计费量不同, 不与顶层 usage 相加; 读取计费量使用顶层 usage.

usageobject

可选的计费量, 视频 token 明细和工具次数. 各字段的单位和省略规则见任务用量字段.

字段类型取值
charge_typestring计费方式: per_request 按次, per_second 按秒, per_token 按 token
requestsinteger计费次数, per_request 时返回. Midjourney 视频的有效 batch_size 计入次数
billed_tokensinteger计价 token 数, per_token 时返回
output_secondsinteger参与计费的输出视频时长, 整数秒, per_second 时返回
input_secondsinteger参与计费的输入视频时长, 整数秒, 为零时省略
input_imagesinteger扣除免费额度后参与计费的输入图片数, 为零时省略
input_tokens, output_tokens, prompt_tokens, completion_tokens, total_tokensinteger视频模型报告的 token 数, 按供应商实际提供情况返回; 按 token 结算后可补齐 total_tokens
tool_usageobject工具次数: web_search, image_search, grounding_queries, 按实际发生返回

charge_type 到 input_images 是计费量, 只与 billing.status=settled 同时返回. 固定价视频按提交时确认的数量返回, 按实际时长或 token 结算的视频按最终结算数量返回. 未返回的字段直接省略, 不补零.

billingobject

可选的平台计费状态和已确认费用. 计费状态独立于任务生成状态, completed 不保证已经结算. 缺少该对象不代表任务免费. 详见价格与实际费用.

属性
statusstring

pending: 生成中, 待结算或退款尚未确认, 省略金额. settled: 已确认最终扣费, 包括提交时一次扣清的固定价视频, 返回实际金额. refunded: 已退款或失败后确认无净扣费, 金额均为 "0".

creditsstring

实际扣除的 ToAPIs Credits, 十进制字符串. 仅在 settled 或 refunded 时返回.

cost_usdstring

同一笔费用的美元金额, 十进制字符串. 返回条件同 credits, 已包含折扣和倍率, 不代表供应商成本.

任务 Webhook 的 data.billing 使用相同的确认条件和取值.

errorobject

错误信息(仅失败时返回)

通常错误码和消息为字符串. Seedance Global 的 error.code 和 error.message 保留上游原始 JSON 值, 包括数字或 null; 上游缺失时不补平台默认值.

属性
codeany

错误代码

messageany

错误描述

任务状态说明

状态说明是否终态建议操作
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 状态码当作业务错误码.

性能建议

视频生成耗时较长,建议:

  1. 使用 ToAPIs 统一任务 Webhook:以 Webhook 为主,轮询为兜底
  2. 合理设置轮询间隔:至少5~10秒并加入随机抖动;遇到429读取 Retry-After 后指数退避
  3. 设置超时时间:长视频生成可能需要5-10分钟,请设置合理的超时
  4. 及时下载保存:视频24小时后过期,请务必及时保存到自己的存储

查询限流和响应头见 异步任务速率限制。批量查询最多 100 个任务 ID。