测试账号

接入联调期间,我们将为您提供一个测试账号。 它和正式账号跑的是同一套接口、同一批字段、同一套错误码、同一套计费逻辑, 唯一的区别是生成任务调用总是返回固定的视频—— 返回的内容来自我们对真实响应的录制。 所以你可以随便跑、反复跑、把失败分支挨个跑一遍,不产生任何费用

和正式账号的差别,就这几条

测试账号正式账号
接口地址、请求体、响应字段完全相同
状态机、错误码、HTTP 状态码完全相同
计费档位、单价、账单金额完全相同
视频内容固定样片你的提示词生成的视频
费用不产生按实际 token 结算
可调模型doubao-seedance-2.0全部

正式使用时我们可以无缝切换到线上模式,你的代码、密钥、base_url 一个字都不用改

三件必须先知道的事

1. 任务耗时是真的

一个 480p / 5 秒的任务,从创建到 succeeded 大约 2 分钟——因为这就是模型本身的真实耗时,我们把它原样回放。 中途会依次经过 queuedrunning, 所以你的轮询循环、超时设置、状态机会被真正地跑到。

注意 queuedrunning 阶段的响应不带 usagerunning 阶段连 resolution 都没有—— 这也是真实行为,不要假设这些字段一直存在。

2. 视频是固定的那一段

video_url 可以正常下载、正常播放、支持 Range 请求、 带正常的 video_url_expires_at。 但无论你请求 480p、720p 还是 1080p,拿到的都是同一段480p / 5 秒的样片——响应 JSON 里的 resolutionusage 会如实反映你的请求, 文件本身是样例。字段是真的,画面是样例。

3. 只能调视频接口

测试账号调 /v1/chat/completions /v1/messages 会返回 403 ERR_SANDBOX_MODEL,因为那些接口后面没有回放层。 需要联调聊天类接口,请单独告诉我们。

主动构造失败链路

这是测试账号最有用的地方。失败分支是接入里最容易漏测的一半—— 正式环境下你没法要求上游"现在给我一个审核拒绝", 而在这里你可以按业务需求来对失败路径做调试。

只需要在原生接口:加一个字段 `sandbox_scenario`。

{
  "model": "doubao-seedance-2.0",
  "content": [{"type": "text", "text": "一只猫在跳舞"}],
  "resolution": "480p",
  "ratio": "16:9",
  "duration": 5,
  "sandbox_scenario": "rejected_invalid_ratio"
}

火山兼容接口没有这个字段,写在提示词里(和 --rs 这类参数一样的写法):

"一只猫在跳舞 --rs 480p --dur 5 --sandbox rejected_invalid_ratio"

可以点名的场景

以下每一条都是我们真实抓取的响应, 错误码和文案都源自实际线上真实请求。

sandbox_scenario你会拿到用来测什么
(不填)正常成功链路默认行为,按你的请求自动匹配分辨率与输入类型
rejected_invalid_ratio400 · invalid_ratio参数取值非法
rejected_bad_duration400 · invalid_seconds时长越界
rejected_unsupported_field400 · unsupported_field请求体里有不认识的字段
rejected_missing_content400 · invalid_request必填字段缺失
rejected_unfetchable_image400 · sdk_error你传的参考图 / 参考视频下载不下来——接入期最常踩的一个
succeeded_t2v_1080p_5s1080p 成功任务高价档账单(和 480p 不同档)
succeeded_v2v_480p_5s带参考视频的成功任务最贵那一档:含视频输入,token 翻倍
succeeded_last_frame_480p_5s响应带 content.last_frame_url尾帧图取用

表里的 codemessage 都是真实响应的原值, 不会被包装成一个笼统的"服务错误"。所以你按 code 分支写的错误处理,在正式账号上遇到同样的问题时会走进同一个分支。

场景名写错会返回 400 并把当前可用的场景列全,不用背。 正式账号发这个参数会被拒绝(400)—— 我们不会悄悄忽略它,否则你会以为自己在测失败分支、实际拿到的是成功。

联调 checklist

下面这九条跑通,接入基本就没有暗雷了。 建议按顺序做,每条都在测试账号上真跑一次。

  1. 认证——用错误的 key 调一次,确认你能识别 401;确认 key 是从配置读的,没有硬编码。
  2. 创建任务——拿到 id(形如 vt_…),确认你把它持久化了。 任务是异步的,进程重启后你得能接着轮询。
  3. 轮询到终态——处理 queued / running 两个中间态, 确认你没有假设 usageresolution 一直存在。建议轮询间隔 ≥ 5 秒。
  4. 下载视频——从 video_url 取到文件;确认你读了 video_url_expires_at在 24 小时内转存。我们不做长期托管。
  5. 失败分支——把上表里的 rejected_* 挨个点一遍, 确认每一种你都能给最终用户一个说得清的提示,而不是"系统错误"。
  6. 取消——对一个已经在跑的任务调 DELETE,你会拿到 409 ERR_CANCEL_REFUSED。 这是真实行为:任务照常跑完、照常计费。 确认你的逻辑按"取消可能不生效"设计,而不是点了就当没了。
  7. 账单字段——确认 cost 块只在任务结算后出现,且你读的是 cost.amount(人民币字符串) 而不是自己按 token 乘一遍。
  8. 列表与分页——按 filter.status 查一次,翻一页,确认你读的是 total 而不是靠 "返回条数 < page_size" 判断结尾。
  9. 重试安全——对同一个任务重复轮询、重复下载, 确认不会重复计费或重复入库。任务 id 是幂等键。

接口细节见 视频生成; 错误码全表见 错误码; 计费口径见 计费与余额