# Seedance 2.0 视频生成 API

> 任务式异步接口：文生视频、首尾帧图生视频、多模态参考生视频，路径与火山引擎方舟完全一致

Seedance 2.0 视频生成采用**异步任务**模式：先提交任务拿到任务 ID，再轮询查询接口获取成片。接口路径、请求体、响应结构与火山引擎方舟保持一致，已有的官方示例代码只需替换 Base URL 与 API Key 即可运行。

<Info>
想先在浏览器里体验？打开 [API 参考 → 创建视频生成任务](/api-reference/create-video-task)，填入你的 `sk-` API Key 即可**试一试**在线发起真实请求。
</Info>

<Tip>
文生视频、图生视频、多模态参考共用同一个接口，仅靠 `content` 数组的组合区分模式。模型清单、定价与常见问题见 [能力总览](/api-capabilities/seedance2/overview)。
</Tip>

<Warning>
**接入前请注意以下差异点，可以避开绝大多数排障时间：**

1. Base URL 为 `https://api.looprouter.com`，完整路径是 `/api/v3/contents/generations/tasks`，`/api` 前缀不能省略。
2. `resolution` 可用档位由 [API Key 所在分组](/user-groups)决定：VIP 组支持 `480p`、`720p`、`1080p`、`4k` 全档位，补贴组支持 `720p`、`1080p`。传入分组外的档位会直接返回 400，不会扣费。
3. 本接口**不支持** `callback_url` 回调，传入会返回 400；请使用轮询查询任务状态。
4. 成功状态是 `succeeded`（不是 `completed`）；成片 `content.video_url` 为临时链接，请在 2 小时内转存。
5. Python `requests` 用户建议加请求头 `Accept-Encoding: identity`，避免个别网络环境下 gzip 解码异常导致响应截断。
</Warning>

## 代码示例

<CodeGroup>

```bash 创建任务（cURL）
curl -X POST "https://api.looprouter.com/api/v3/contents/generations/tasks" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY" \
  -d '{
    "model": "doubao-seedance-2-0-260128",
    "content": [
      {
        "type": "text",
        "text": "雨后的城市街道，霓虹灯倒映在积水中，一只橘猫从画面左侧慢慢走过"
      }
    ],
    "resolution": "720p",
    "ratio": "16:9",
    "duration": 5
  }'

# 返回：{"id": "task_xxxx"} —— 只返回任务 ID，视频需轮询查询接口获取
```

```python 完整流程（Python）
import time
import requests

BASE = "https://api.looprouter.com"
HEADERS = {
    "Authorization": "Bearer sk-你的APIKey",
    "Accept-Encoding": "identity",  # 避免个别环境 gzip 解码异常
}

# 1. 创建任务
resp = requests.post(
    f"{BASE}/api/v3/contents/generations/tasks",
    headers=HEADERS,
    json={
        "model": "doubao-seedance-2-0-260128",
        "content": [
            {"type": "text", "text": "雨后的城市街道，霓虹灯倒映在积水中，一只橘猫从画面左侧慢慢走过"}
        ],
        "resolution": "720p",
        "ratio": "16:9",
        "duration": 5,
        # "generate_audio": True,   # 默认开启同步音频
        # "seed": 42,               # 固定随机种子，结果更可复现
    },
)
resp.raise_for_status()
task_id = resp.json()["id"]
print("任务已创建:", task_id)

# 2. 轮询任务状态（建议 15~30 秒一次）
while True:
    task = requests.get(
        f"{BASE}/api/v3/contents/generations/tasks/{task_id}",
        headers=HEADERS,
    ).json()
    status = task["status"]
    print("当前状态:", status)
    if status in ("succeeded", "failed", "cancelled", "expired"):
        break
    time.sleep(20)

# 3. 下载成片（下载时不要携带 Authorization 头）
if status == "succeeded":
    video_url = task["content"]["video_url"]
    with requests.get(video_url, stream=True) as r:
        r.raise_for_status()
        with open("output.mp4", "wb") as f:
            for chunk in r.iter_content(chunk_size=1 << 20):
                f.write(chunk)
    print("已保存 output.mp4")
else:
    print("任务未成功:", task.get("error"))
```

```python 图生视频与多模态参考（Python）
# 模式二：首尾帧图生视频 —— 用两张图约束视频的第一帧和最后一帧
first_last_frame_body = {
    "model": "doubao-seedance-2-0-260128",
    "content": [
        {"type": "text", "text": "镜头缓缓推进，人物转身微笑"},
        {"type": "image_url", "image_url": {"url": "https://example.com/first.jpg"}, "role": "first_frame"},
        {"type": "image_url", "image_url": {"url": "https://example.com/last.jpg"}, "role": "last_frame"},
    ],
    "resolution": "1080p",
    "duration": 5,
}

# 模式三：多模态参考 —— 参考图 / 参考视频 / 参考音频自由组合
multimodal_body = {
    "model": "doubao-seedance-2-0-260128",
    "content": [
        {"type": "text", "text": "图片1中的角色在草地上奔跑，参考视频1的运镜节奏"},
        {"type": "image_url", "image_url": {"url": "asset://asset-20260709190143-ntwhb"}, "role": "reference_image"},
        # {"type": "video_url", "video_url": {"url": "https://example.com/ref.mp4"}, "role": "reference_video"},
        # {"type": "audio_url", "audio_url": {"url": "https://example.com/voice.mp3"}, "role": "reference_audio"},
    ],
    "resolution": "720p",
    "ratio": "adaptive",
    "duration": -1,  # -1 表示由模型自行决定时长，按实际产出计费
}
```

```javascript Node.js
const BASE = "https://api.looprouter.com";
const KEY = process.env.LOOPROUTER_API_KEY;

async function main() {
  // 创建任务
  const createRes = await fetch(`${BASE}/api/v3/contents/generations/tasks`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${KEY}`,
    },
    body: JSON.stringify({
      model: "doubao-seedance-2-0-260128",
      content: [
        { type: "text", text: "雨后的城市街道，霓虹灯倒映在积水中，一只橘猫从画面左侧慢慢走过" },
      ],
      resolution: "720p",
      ratio: "16:9",
      duration: 5,
    }),
  });
  const { id } = await createRes.json();
  console.log("任务已创建:", id);

  // 轮询
  for (;;) {
    await new Promise((r) => setTimeout(r, 20000));
    const task = await (
      await fetch(`${BASE}/api/v3/contents/generations/tasks/${id}`, {
        headers: { Authorization: `Bearer ${KEY}` },
      })
    ).json();
    console.log("当前状态:", task.status);
    if (["succeeded", "failed", "cancelled", "expired"].includes(task.status)) {
      if (task.status === "succeeded") console.log("视频地址:", task.content.video_url);
      else console.error("任务未成功:", task.error);
      break;
    }
  }
}

main();
```

```bash 查询任务（cURL）
curl "https://api.looprouter.com/api/v3/contents/generations/tasks/task_xxxx" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY"
```

</CodeGroup>

## 请求参数速查

`POST /api/v3/contents/generations/tasks`，请求头 `Authorization: Bearer sk-...`。

| 参数 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `model` | string | 是 | — | 如 `doubao-seedance-2-0-260128`，可用模型以控制台「模型广场」为准 |
| `content` | array | 是 | — | 生成素材数组，见下方[内容项说明](#content-数组) |
| `resolution` | string | 否 | 上游默认 | `480p` / `720p` / `1080p` / `4k`，可用档位依[分组](/user-groups)（VIP 组全档位，补贴组 `720p` / `1080p`），分组外档位返回 400 且不扣费 |
| `ratio` | string | 否 | `adaptive` | `16:9`、`4:3`、`1:1`、`3:4`、`9:16`、`21:9`、`adaptive` |
| `duration` | int | 否 | `5` | 输出时长（秒），范围 4–15；传 `-1` 由模型决定并按实际产出计费 |
| `generate_audio` | bool | 否 | `true` | 是否生成与画面同步的音频（人声/音效/配乐） |
| `watermark` | bool | 否 | `false` | 是否叠加 AI 生成水印 |
| `seed` | int | 否 | `-1` | 随机种子；相同种子产出相近（非完全一致）的结果 |
| `return_last_frame` | bool | 否 | `false` | 成功后额外返回末帧图片，便于多段续接 |
| `execution_expires_after` | int | 否 | `172800` | 任务执行超时（秒），超时未完成转为 `expired` |

<Warning>
`callback_url` 在本平台**不受支持**，传入会返回 400。Seedance 1.x 的 `frames`、`camera_fixed` 等参数对 2.0 模型无效，请勿依赖。
</Warning>

### content 数组

每个元素为一个内容项，`type` 决定其结构：

| type | 结构 | role 取值 | 说明 |
| --- | --- | --- | --- |
| `text` | `{"type":"text","text":"..."}` | — | 提示词。建议中文 ≤500 字、英文 ≤1000 词；台词放在双引号内可提升配音效果 |
| `image_url` | `{"type":"image_url","image_url":{"url":"..."},"role":"..."}` | `first_frame` / `last_frame` / `reference_image` | 支持公网 URL、Base64 data URI、`asset://素材ID` |
| `video_url` | `{"type":"video_url","video_url":{"url":"..."},"role":"reference_video"}` | `reference_video` | 参考视频，最多 3 个；携带视频输入享受[计费折扣](/api-capabilities/seedance2/overview#模型定价) |
| `audio_url` | `{"type":"audio_url","audio_url":{"url":"..."},"role":"reference_audio"}` | `reference_audio` | 参考音频 wav/mp3，单段 2–15 秒，最多 3 段，不能单独出现 |

图片要求：jpeg/png/webp/bmp/tiff/gif/heic/heif，宽高比 (0.4, 2.5)，边长 (300, 6000) 像素，小于 30MB。**真实人脸图片不能直接作为参考图**，需先走 [素材库](/asset-management/asset-library) 与 [真人认证](/asset-management/real-person)，再以 `asset://` 引用。

### 生成模式

| 模式 | content 组合 |
| --- | --- |
| 文生视频 | 1 个 `text` |
| 首帧图生视频 | 可选 `text` + 1 个 `image_url`（role 可省略） |
| 首尾帧图生视频 | 可选 `text` + 2 个 `image_url`（role 必须分别为 `first_frame`、`last_frame`） |
| 多模态参考 | `text` + 0–9 张参考图 + 0–3 个参考视频 + 0–3 段参考音频（至少 1 图或 1 视频） |

三种图片用法互斥：同一请求中不能混用首帧/首尾帧与参考图。

## 查询任务

`GET /api/v3/contents/generations/tasks/{task_id}`

任务状态机：`queued → running → succeeded / failed / cancelled / expired`。任务记录长期保留，可随时回查。

成功响应示例：

```json
{
  "id": "task_xxxx",
  "model": "doubao-seedance-2-0-260128",
  "status": "succeeded",
  "content": {
    "video_url": "https://api.looprouter.com/.../output.mp4?...",
    "last_frame_url": ""
  },
  "usage": {
    "completion_tokens": 246840,
    "total_tokens": 246840
  },
  "seed": 42,
  "resolution": "720p",
  "ratio": "16:9",
  "duration": 5,
  "framespersecond": 24,
  "generate_audio": true,
  "created_at": 1752940800,
  "updated_at": 1752941020
}
```

<Warning>
成片地址在 `content.video_url` 字段，为**临时签名链接（约 2 小时有效）**，请及时转存；下载时请求中**不要**携带 `Authorization` 头。
</Warning>

<Info>
`usage.total_tokens` 为上游按「时长 × 分辨率像素 × 帧率」口径折算的视频 token 数，是结算依据。使用 `duration: -1` 或 `ratio: adaptive` 时，以响应中回填的实际值为准。
</Info>

## 任务列表与取消

本平台在原厂接口之外额外提供两个管理接口：

**列出任务** — `GET /api/v3/contents/generations/tasks`

| 查询参数 | 说明 |
| --- | --- |
| `page_num` | 页码，默认 1 |
| `page_size` | 每页数量，默认 20，最大 500 |
| `filter.status` | 按状态过滤：`queued` / `running` / `succeeded` / `failed` / `cancelled` |
| `filter.model` | 按模型过滤 |
| `filter.task_ids` | 按任务 ID 列表过滤 |

响应为 `{"items": [...], "total": n}`，元素结构与查询单个任务一致。

**取消/删除任务** — `DELETE /api/v3/contents/generations/tasks/{task_id}`

排队中的任务可以取消；`running` 状态的任务不可取消（返回 400 `invalid_task_status`）。成功返回 `{}`。

## 错误响应

所有错误采用与火山引擎一致的结构：

```json
{
  "error": {
    "code": "invalid_request",
    "message": "具体错误描述 (request id: ...)",
    "param": "",
    "type": "BadRequest"
  }
}
```

| HTTP 状态码 | type | 常见原因 |
| --- | --- | --- |
| 400 | `BadRequest` | 缺少 `model`/`content`；`resolution` 不在当前[分组](/user-groups)可用档位内；传了 `callback_url`；取消运行中任务 |
| 401 | `Unauthorized` | API Key 缺失或无效 |
| 403 | `Forbidden` | 令牌无权访问该模型；内容审核未通过（如真实人脸直传） |
| 404 | `NotFound` | 任务 ID 不存在或不属于当前账号 |
| 429 | `RateLimitExceeded` | 当前分组上游负载已饱和，请稍后再试 |
| 5xx | `InternalServerError` | 服务端异常，建议指数退避后重试 |

<Info>
429 与 5xx 建议采用指数退避重试（如 2s → 4s → 8s）。参数校验失败（400）与内容审核拒绝（403）**均不扣费**；已预扣的失败任务会自动退款。
</Info>

## 相关文档

<CardGroup cols={3}>
  <Card title="能力总览与定价" icon="circle-info" href="/api-capabilities/seedance2/overview">
    模型清单、技术规格、计费规则
  </Card>
  <Card title="素材引用实战" icon="wand-magic-sparkles" href="/asset-management/asset-reference">
    从上传素材到角色一致性生成的完整链路
  </Card>
  <Card title="在线调试" icon="flask" href="/api-reference/create-video-task">
    在文档内直接试一试
  </Card>
</CardGroup>
