测试账号
接入联调期间,我们将为您提供一个测试账号。 它和正式账号跑的是同一套接口、同一批字段、同一套错误码、同一套计费逻辑, 唯一的区别是生成任务调用总是返回固定的视频—— 返回的内容来自我们对真实上游响应的录制。 所以你可以随便跑、反复跑、把失败分支挨个跑一遍,不产生任何费用,也不需要先充值。
和正式账号的差别,就这几条
| 测试账号 | 正式账号 | |
|---|---|---|
| 接口地址、请求体、响应字段 | 完全相同 | |
| 状态机、错误码、HTTP 状态码 | 完全相同 | |
| 计费档位、单价、计费秒数 | 完全相同 | |
| 账单金额 | cost.amount 恒为 "0.00",并带 cost.sandbox: true;不扣余额、不进账单 | 按档位单价结算 |
| 余额 | 不需要充值;余额为 0 也能提交(控制台的"余额低"提示可以忽略) | 提交前预检余额,不足返回 402 |
| 视频内容 | 固定样片(每个模型一段 720p 短片) | 你的提示词生成的视频 |
| 可调模型 | seedance-2.0-custom · seedance-2.0-fast-custom · seedance-2.5-custom(用你的 key 调 GET /api/v1/models 看到的就是这三个) | 目录里的全部模型 |
| 参数组合 | 模型支持的全部都能提交;画面不随之变化,字段随之变化 | 模型支持的全部 |
正式使用时我们可以无缝切换到线上模式,你的代码、密钥、base_url 一个字都不用改。
三件必须先知道的事
1. 任务耗时是真的
一个任务从创建到 succeeded 要 3–4 分钟—— 因为这就是模型本身的真实耗时,我们把它原样回放。 中途会依次经过 queued 和 running, 所以你的轮询循环、超时设置、状态机会被真正地跑到。
注意 queued 和 running 阶段的响应没有 video_url、cost,succeeded 之前也没有 fps、seed—— 这也是真实行为,不要假设这些字段一直存在。
2. 字段是真的,画面是样例
无论你传什么分辨率、时长、参考图 / 参考视频 / 音频,只要参数通过校验, 任务都会受理并跑完;响应里的 resolution、duration、cost.tier、cost.unit_price、cost.quantity 都按你的请求计算(4k、30 秒、带参考视频就是 vin_4k × 30),所以各档位的账单字段都能在这里核对。 但 video_url 拿到的永远是该模型的固定样片:
| 模型 | 样片 | 耗时 |
|---|---|---|
seedance-2.0-custom | 720p · 5 秒 | 约 3 分钟 |
seedance-2.0-fast-custom | 720p · 4 秒 | 约 4 分钟 |
seedance-2.5-custom | 720p · 4 秒 | 约 4 分钟 |
样片可以正常下载、正常播放、支持 Range 请求、带正常的 video_url_expires_at。 参数校验和正式账号是同一段代码,在回放之前执行: 给这些模型传 watermark、媒体 URL 不是公网地址、时长越界, 在测试账号上会得到和正式账号一模一样的拒绝。
3. 只能调视频接口
测试账号调 /v1/chat/completions 或 /v1/messages 会返回 403 ERR_SANDBOX_MODEL,消息里会列出这个账号能调的模型, 因为对话接口后面没有回放层。需要联调聊天类接口,请单独告诉我们。
主动构造失败链路
这是测试账号最有用的地方。失败分支是接入里最容易漏测的一半—— 正式环境下你没法要求上游"现在给我一个 400", 而在这里你可以点名要一条录制过的失败响应。
原生接口加一个字段 sandbox_scenario:
{
"model": "seedance-2.0-fast-custom",
"content": [{"type": "text", "text": "一只猫在跳舞"}],
"resolution": "720p",
"duration": 4,
"sandbox_scenario": "rejected_ytfast_short_duration"
}火山兼容接口没有这个字段,写在提示词里(和 --rs 这类参数一样的写法):
"一只猫在跳舞 --rs 720p --dur 4 --sandbox rejected_ytfast_short_duration"可以点名的场景
以下每一条都是我们真实抓取的响应, 错误码和文案都是上游原值。
| sandbox_scenario | 模型 | 你会拿到 | 用来测什么 |
|---|---|---|---|
| (不填) | 三个都行 | 正常成功链路 | 默认行为,任何通过校验的请求都走这条 |
succeeded_yt20_720p_5s · succeeded_ytfast_720p_4s · succeeded_yt25_720p_4s | 各自的模型 | 与不填等价 | 一般不需要;写着是为了场景名齐全 |
rejected_ytfast_short_duration | seedance-2.0-fast-custom | 400 · invalid_request · Invalid request parameters: HTTP 400 | 上游在创建阶段就拒绝,没有任务 id、不计费—— 确认你处理了"提交就失败"这一分支。点名时任何合法请求都会拿到这条响应 |
失败场景只在点名时回放:不写 sandbox_scenario 的请求一律走成功链路。 场景名写错会返回 400 并把当前模型可用的场景列全,不用背。正式账号发这个参数会被拒绝(400)—— 我们不会悄悄忽略它,否则你会以为自己在测失败分支、实际拿到的是成功。
另外两条正式账号上也会遇到、测试账号上同样能触发的错误, 不需要点名:不支持的参数(400 ERR_UNSUPPORTED_PARAMETER, 消息指明是哪个参数)和取消被拒(下文)。
联调 checklist
下面这九条跑通,接入基本就没有暗雷了。 建议按顺序做,每条都在测试账号上真跑一次。
- 认证——用错误的 key 调一次,确认你能识别
401 ERR_AUTH_FAILED;确认 key 是从配置读的,没有硬编码。 - 创建任务——拿到
id(形如vt_…),确认你把它持久化了。 任务是异步的,进程重启后你得能接着轮询。 - 轮询到终态——处理
queued/running两个中间态, 确认你没有假设video_url或cost一直存在。建议轮询间隔 ≥ 10 秒,任务要跑 3–4 分钟。 - 下载视频——从
video_url取到文件;确认你读了video_url_expires_at并在 24 小时内转存。我们不做长期托管。 - 失败分支——点名
rejected_ytfast_short_duration跑一次创建期失败,再传一个不支持的参数跑一次ERR_UNSUPPORTED_PARAMETER, 确认每一种你都能给最终用户一个说得清的提示,而不是"系统错误"。 - 取消——对一个已经在跑的任务调
DELETE,你会拿到409 ERR_CANCEL_REFUSED。 这是真实行为:这三个模型不支持取消,任务照常跑完; 正式账号上照常计费,测试账号的消息会注明test account: no charge。 确认你的逻辑按"取消可能不生效"设计,而不是点了就当没了。 - 账单字段——确认
cost块只在任务结算后出现,且你读的是cost.amount(人民币字符串) 而不是自己按单价乘一遍。测试账号下cost.amount恒为"0.00"并带cost.sandbox: true;cost.tier、cost.unit_price、cost.quantity与正式账号一致,可以拿来核对档位。计费接口和控制台的用量页会列出每一次调用,金额同样为 0。 - 列表与分页——按
filter.status查一次,翻一页,确认你读的是total而不是靠 "返回条数 < page_size" 判断结尾。 - 重试安全——对同一个任务重复轮询、重复下载, 确认不会重复计费或重复入库。任务 id 是幂等键。