Seedance 2.0 API 不是同步返回视频的接口,而是一个异步视频生成任务。生产接入时,正确路径是:创建任务,保存返回的任务 ID,轮询或接收回调直到终态,把返回的 video_url 转存到自己的对象存储,再用本地任务记录控制重试。
如果走 BytePlus ModelArk 国际路线,当前任务创建端点是 https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks,Seedance 2.0 标准模型 ID 是 dreamina-seedance-2-0-260128,Fast 模型 ID 是 dreamina-seedance-2-0-fast-260128。如果走中国区火山方舟,端点和模型 ID 要换成中国区路线,不要把 dreamina-* 和 doubao-* 混在同一套配置里。

先提交一个异步任务
创建任务只负责启动生成,不负责返回最终视频。你的服务应在提交前确认模型路线、提示词、参考素材、比例、分辨率、时长、是否生成音频、回调地址和用户身份标识。提交成功后,把 provider 返回的任务 ID 写入自己的 job 表。
bashcurl -X POST "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks" \ -H "Authorization: Bearer $ARK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "dreamina-seedance-2-0-260128", "content": [ { "type": "text", "text": "A quiet product demo shot, slow camera move, clean studio light" } ], "ratio": "16:9", "resolution": "720p", "duration": 5, "generate_audio": false, "return_last_frame": true, "callback_url": "https://example.com/webhooks/seedance" }'
这里最容易出错的是超时重试。如果 HTTP 客户端没收到响应,不要直接再发一次生成请求;先查本地 job 是否已经保存了 provider task ID。只要已有 task ID,就恢复轮询,而不是重新提交。
用轮询或回调推进状态
查询任务接口返回的是任务状态,而不是线性进度。应用层可以把状态收敛成一张有限状态机:
| 状态 | 含义 | 处理方式 |
|---|---|---|
queued | 已入队,尚未运行 | 退避轮询或等待回调 |
running | 正在生成 | 继续等待,不要重新提交 |
succeeded | 视频已生成 | 读取并转存 content.video_url |
failed | 任务失败 | 保存 error.code 和 error.message |
expired | 超过执行窗口 | 根据业务决定是否允许用户重新提交 |
cancelled | 队列任务被取消 | 停止轮询并回写取消状态 |
bashcurl -X GET \ "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks/$TASK_ID" \ -H "Authorization: Bearer $ARK_API_KEY"
回调可以降低延迟,但不要只依赖回调。部署、签名校验、网络抖动都可能让回调丢失;保留一个带退避的轮询修复器,才能把卡住的任务拉回一致状态。
成功后立即下载并转存
任务成功后,响应里的 content.video_url 是 MP4 地址,但它不应该成为你的长期播放地址。官方响应说明生成视频会在 24 小时后清理,所以成功处理器应立即把视频复制到自己的对象存储。
tsasync function copySeedanceVideo(job, task) { const videoUrl = task.content?.video_url; if (!videoUrl) throw new Error("Seedance succeeded without video_url"); const res = await fetch(videoUrl); if (!res.ok) throw new Error(`download failed: ${res.status}`); await storage.putObject({ key: `seedance/${job.id}/output.mp4`, body: res.body, contentType: "video/mp4", }); }
同时保存 provider 原始响应:模型 ID、任务状态、seed、ratio、resolution、duration 或 frames、generate_audio 和 usage.total_tokens。这些字段会在客服排障、成本核对和结果复现时用到。

参考素材要写进 content
Seedance 2.0 的参考图、参考视频和参考音频不是简单附件,而是生成模式的一部分。首帧图生视频使用 first_frame,首尾帧使用 first_frame 与 last_frame,多模态参考生成使用 reference_image、reference_video 和 reference_audio。
json{ "model": "dreamina-seedance-2-0-260128", "content": [ { "type": "text", "text": "Use [image 1] as the product reference and keep the motion minimal." }, { "type": "image_url", "image_url": { "url": "https://cdn.example.com/reference-product.webp" }, "role": "reference_image" } ], "ratio": "16:9", "duration": 5, "generate_audio": false }
提交前先做素材校验:图片尺寸、格式、宽高比和大小要合规;视频参考只放到支持视频输入的 Seedance 2.0 路线;音频不能单独提交,必须至少配合图片或视频;涉及真人素材时,要把授权和合规检查放在 API 调用前。
重试必须幂等
Seedance 2.0 接入里最贵的 bug 是重复生成。不要让 HTTP 客户端决定是否重放创建请求,而要用自己的 job 表和 request hash 控制。
request hash 可以由模型路线、模型 ID、规范化提示词、参考素材 URL 或 asset ID、输出参数和用户标识组成。同一个 hash 已经有 job 时,返回原 job;只有本地 job 明确没有 provider task ID,且上一次创建确实没有完成,才允许重试创建。
| 操作 | 重试规则 |
|---|---|
| 创建任务,尚未保存 task ID | 查 job 和 hash 后再重试 |
| 已保存 task ID | 不再创建,恢复轮询 |
| 查询任务 | 网络错误或 5xx 可退避重试 |
| 处理回调 | 状态迁移幂等即可重复执行 |
| 下载视频 | 临时 URL 过期前可重试 |
| provider 返回失败 | 先分类错误,不自动重复生成 |

上线前检查
- 模型 ID、端点和计费路线绑定在同一套配置里。
- 创建任务后先保存 provider task ID,再进入轮询。
- 回调处理可以重复执行,不会倒退状态。
- 轮询有退避和最大等待时间。
video_url在 24 小时窗口内被复制到自己的存储。- 参考素材在提交前完成格式、大小、时长和授权校验。
- 重试逻辑不会为同一个业务 job 创建多个付费生成任务。
常见问题
Seedance 2.0 API 是同步接口吗?
不是。创建接口返回任务 ID,真正的视频要等任务进入 succeeded 后再通过查询结果里的 content.video_url 获取。
应该用轮询还是回调?
生产环境建议两者都要:回调用于快速更新,轮询用于修复丢失的回调和异常部署窗口。
返回的视频 URL 能长期使用吗?
不建议。它是临时 MP4 地址,官方响应说明生成视频会在 24 小时后清理,成功后应立即转存。
创建请求超时时怎么办?
先查本地 request hash 和 job 记录。如果已经有 provider task ID,就继续轮询;如果确实没有保存 task ID,再用同一个本地 job 重试创建。
