> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cdhyzxwl.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 调用Seedance视频模型

本文面向需要通过本站调用 Seedance 视频模型的下游开发者，介绍接口选择、请求参数、视频输入方式、任务轮询以及计费规则。

## 1. 先记住这三件事

1. **Seedance 不使用 `/v1/responses`。** 该路径进入 Responses 转发链路，不会进入 Seedance 的异步视频任务适配器。
2. **提交接口是 `POST /v1/video/generations`。** 提交成功后会立即返回任务 ID，不会同步等待视频生成完成。
3. **任务完成后再轮询。** 使用 `GET /v1/video/generations/{task_id}` 查询状态和结果。

本站也提供 OpenAI Video 风格的 `/v1/videos` 路径，但它仍然是视频任务接口，不是 Responses API。首次接入建议使用下面教程中的 JSON 接口。

## 2. 调用前准备

调用前需要先确认以下信息：

* 本站访问地址： `https://teio.me`；
* 可用的 API Token；
* Token 所属分组是否允许访问目标模型；
* 目标模型名称，例如 `doubao-seedance-2-0-260128`；

## 3. 一次完整调用的流程

### 第一步：提交任务

```bash theme={null}
curl -X POST "https://teio.me/v1/video/generations" \
  -H "Authorization: Bearer $NEW_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao-seedance-2-0-260128",
    "prompt": "一只橘猫在阳光下的窗台上伸懒腰，电影感，镜头缓慢推进",
    "duration": 5,
    "metadata": {
      "resolution": "720P",
      "ratio": "16:9",
      "generate_audio": true,
      "watermark": false
    }
  }'
```

提交成功时，响应通常类似：

```json theme={null}
{
  "id": "task_xxxxxxxxx",
  "task_id": "task_xxxxxxxxx",
  "object": "video",
  "model": "doubao-seedance-2-0-260128",
  "status": "queued",
  "progress": 0,
  "created_at": 1770000000
}
```

请保存 `id` 和 `task_id` 在本站的视频提交响应中通常是同一个公开任务 ID。

### 第二步：轮询任务状态

```bash theme={null}
curl "https://teio.me/v1/video/generations/task_xxxxxxxxx" \
  -H "Authorization: Bearer $NEW_API_TOKEN"
```

该路径返回本站通用任务结构，示例：

```json theme={null}
{
  "code": "success",
  "message": "",
  "data": {
    "task_id": "task_xxxxxxxxx",
    "status": "SUCCESS",
    "progress": "100%",
    "result_url": "https://cdn.example.com/result.mp4",
    "data": {
      "id": "upstream_task_id",
      "status": "succeeded",
      "resolution": "720P",
      "duration": 5,
      "usage": {
        "total_tokens": 50638
      }
    }
  }
}
```

常见状态如下：

| `data.status` | 含义   | 应用行为                  |
| ------------- | ---- | --------------------- |
| `SUBMITTED`   | 已提交  | 继续轮询                  |
| `QUEUED`      | 排队中  | 继续轮询                  |
| `IN_PROGRESS` | 生成中  | 继续轮询                  |
| `SUCCESS`     | 生成成功 | 读取 `result_url`       |
| `FAILURE`     | 生成失败 | 读取 `fail_reason`，停止轮询 |

建议轮询间隔为 2 至 5 秒，并设置最大等待时间。不要高频并发轮询同一个任务。

### 第三步：读取视频

任务成功后，优先使用响应中的 `result_url`。是否允许代理下载以及结果 URL 的有效期，取决于上游返回策略。**<u>下游应及时下载或转存视频，不要长期依赖上游临时 URL</u>**。

## 4. 请求参数

### 4.1 顶层参数

| 参数         | 类型              | 必填 | 说明                                               |
| ---------- | --------------- | -- | ------------------------------------------------ |
| `model`    | string          | 是  | Seedance 模型名称。                                   |
| `prompt`   | string          | 是  | 视频生成提示词。不能为空。                                    |
| `duration` | integer         | 否  | 视频时长，单位为秒。建议显式填写。本站网关上限为 3600 秒，但模型通常有更小的官方限制。   |
| `seconds`  | string          | 否  | `duration` 的兼容写法，例如 `"5"`。建议不要与 `duration` 同时填写。 |
| `image`    | string          | 否  | 单张图片 URL 的简写，本站会将其转换为图片输入。                       |
| `images`   | array of string | 否  | 多张图片 URL 的简写。                                    |
| `metadata` | object          | 否  | Seedance 专属字段和多媒体 `content` 放在这里。                |

`prompt` 是必填项，即使请求里有参考图片、参考视频或参考音频，也应把文字描述放在顶层 `prompt` 中。

### 4.2 `metadata` 中的常用字段

Seedance 上游字段通过 `metadata` 透传。常用字段如下：

| 字段                        | 类型      | 示例                                      | 作用                    |
| ------------------------- | ------- | --------------------------------------- | --------------------- |
| `resolution`              | string  | `"720P"`                                | 输出分辨率，也参与视频单价匹配。      |
| `ratio`                   | string  | `"16:9"`                                | 输出画幅比例。               |
| `generate_audio`          | boolean | `true`                                  | 是否生成音频。               |
| `watermark`               | boolean | `false`                                 | 是否添加水印。               |
| `return_last_frame`       | boolean | `true`                                  | 是否返回尾帧。               |
| `callback_url`            | string  | `"https://client.example.com/callback"` | 上游任务回调地址，是否生效取决于上游能力。 |
| `service_tier`            | string  | `"default"`                             | 上游服务等级。               |
| `execution_expires_after` | integer | `3600`                                  | 任务执行过期时间，单位以上游定义为准。   |
| `draft`                   | boolean | `false`                                 | 是否使用草稿模式。             |
| `seed`                    | integer | `12345`                                 | 随机种子。                 |
| `frames`                  | integer | `120`                                   | 帧数。                   |
| `camera_fixed`            | boolean | `false`                                 | 是否固定摄像机。              |
| `safety_identifier`       | string  | `"user-123"`                            | 上游安全标识。               |
| `priority`                | integer | `0`                                     | 上游任务优先级。              |
| `content`                 | array   | 见下文                                     | 参考图片、视频、音频等多媒体输入。     |

上游对具体模型的参数范围可能更严格。例如某个模型只允许若干种时长或分辨率时，即使本站网关接受了字段，上游仍可能返回参数错误。

### 4.3 重要规则：文字放 `prompt`，媒体放 `metadata.content`

本站会自动把顶层 `prompt` 转成上游的文本内容。`metadata.content` 中的文字项会被网关移除，因此不要依赖下面这种写法：

```json theme={null}
{
  "model": "doubao-seedance-2-0-260128",
  "prompt": "请生成视频",
  "metadata": {
    "content": [
      {"type": "text", "text": "这段文字不会作为额外内容保留"}
    ]
  }
}
```

正确做法是把完整文字放在顶层：

```json theme={null}
{
  "model": "doubao-seedance-2-0-260128",
  "prompt": "请生成一段城市夜景视频，镜头从街道缓慢上升",
  "metadata": {
    "content": [
      {
        "type": "image_url",
        "image_url": {"url": "https://cdn.example.com/reference.jpg"},
        "role": "reference_image"
      }
    ]
  }
}
```

## 5. 输入图片、视频和音频

参考媒体 URL 应能被上游服务器访问。生产环境建议使用稳定的 HTTPS 公网 URL，并确保 URL 在任务排队和执行期间不会过期。

### 5.1 文生视频

```json theme={null}
{
  "model": "doubao-seedance-2-0-260128",
  "prompt": "一片竹林在微风中摇曳，阳光穿过竹叶，写实风格",
  "duration": 5,
  "metadata": {
    "resolution": "480P",
    "ratio": "16:9",
    "generate_audio": true
  }
}
```

### 5.2 图生视频

单图可以使用顶层 `image` 简写：

```json theme={null}
{
  "model": "doubao-seedance-2-0-260128",
  "prompt": "让画面中的人物自然转身并看向镜头，保持人物外观一致",
  "image": "https://cdn.example.com/start-frame.jpg",
  "duration": 5,
  "metadata": {
    "resolution": "720P",
    "ratio": "9:16"
  }
}
```

如果需要标记图片的用途，使用 `metadata.content`：

```json theme={null}
{
  "model": "doubao-seedance-2-0-260128",
  "prompt": "以第一张图为首帧，以第二张图为尾帧，镜头平滑过渡",
  "duration": 8,
  "metadata": {
    "resolution": "1080P",
    "content": [
      {
        "type": "image_url",
        "image_url": {"url": "https://cdn.example.com/first.jpg"},
        "role": "reference_image"
      },
      {
        "type": "image_url",
        "image_url": {"url": "https://cdn.example.com/last.jpg"},
        "role": "reference_image"
      }
    ]
  }
}
```

### 5.3 视频生视频或参考视频

参考视频必须放在 `metadata.content` 中，并使用 `type: "video_url"`：

```json theme={null}
{
  "model": "doubao-seedance-2-0-260128",
  "prompt": "延续参考视频的运动节奏，把场景改为海边日落",
  "duration": 5,
  "metadata": {
    "resolution": "720P",
    "content": [
      {
        "type": "video_url",
        "video_url": {"url": "https://cdn.example.com/reference.mp4"},
        "role": "reference_video"
      }
    ]
  }
}
```

**只有被识别为 `video_url` 的内容才会被计为“含视频输入”。** 把视频 URL 塞进 `prompt`、普通字符串字段或未识别的自定义字段，不会触发含视频输入价格。

### 5.4 参考音频

```json theme={null}
{
  "model": "doubao-seedance-2-0-260128",
  "prompt": "制作一段与音乐节奏同步的霓虹城市宣传片",
  "duration": 10,
  "metadata": {
    "generate_audio": true,
    "content": [
      {
        "type": "audio_url",
        "audio_url": {"url": "https://cdn.example.com/music.mp3"},
        "role": "reference_audio"
      }
    ]
  }
}
```

图片、视频和音频可以同时放入 `metadata.content`。每个内容项都应包含对应的 `type` 和 URL 对象：

```json theme={null}
{
  "type": "image_url",
  "image_url": {"url": "https://cdn.example.com/image.jpg"},
  "role": "reference_image"
}
```

可用的媒体类型是 `image_url`、`video_url` 和 `audio_url`。`role` 用于告诉上游媒体的用途，例如 `reference_image`、`reference_video` 或 `reference_audio`。

## 6. 视频计费规则

### 6.1 计费由四个因素共同决定

Seedance 的视频定价不是简单的“调用一次固定扣费”，主要由以下因素决定：

1. **实际消耗的 `total_tokens`**：任务完成后由上游返回；
2. **是否有视频输入**：本站从 `metadata.content` 是否包含 `video_url` 判断；
3. **输出分辨率**：本站优先使用上游任务结果中的实际 `resolution`；
4. **用户分组倍率**：管理员可以对不同用户分组设置不同倍率。

其中，视频输入和分辨率决定“每百万 Token 单价”，而实际 Token 数量决定最终用量。

这里的“含视频输入”特指请求里存在参考视频，即 `metadata.content` 中包含 `video_url`。所有请求最终都会生成视频，但“生成了视频”本身不等于“含视频输入”；只有图片或音频输入也不会触发含视频输入价格。

### 6.2 最终结算公式

本站内部使用额度（quota）记账。最终视频额度大致按下面的公式计算：

```text theme={null}
actualQuota = totalTokens / 1,000,000
            × pricePerMillion
            × QuotaPerUnit
            × groupRatio
```

参数含义：

| 参数                | 含义                                             |
| ----------------- | ---------------------------------------------- |
| `totalTokens`     | 上游任务完成时返回的 `usage.total_tokens`。               |
| `pricePerMillion` | 根据视频输入和实际分辨率选出的单价。                             |
| `QuotaPerUnit`    | 额度和计费货币的换算比例，本站默认是 500,000，即500000quota = \$1。 |
| `groupRatio`      | 用户所在分组倍率                                       |

例如：

* 实际消耗 `50,638` Token；
* 输出分辨率为 `480P`；
* 不含参考视频；
* 单价为 `46 / 百万 Token`；
* 分组倍率为 `1`。

则：

```text theme={null}
50,638 / 1,000,000 × 46 × 500,000 × 1
= 1,164,674 quota
```

如果同样的任务包含参考视频，单价按 `28 / 百万 Token` 计算：

```text theme={null}
50,638 / 1,000,000 × 28 × 500,000 × 1
= 708,932 quota
```

这两个数字只是演示计算方式。实际 `total_tokens`、实际输出分辨率和管理员配置可能不同。

### 6.3 预扣费和最终结算

视频是异步任务。为了防止用户提交任务后余额被其他请求消耗，本站会在提交时先预留一部分额度，再在任务完成后按实际用量结算差额。

预扣估算通常使用：

```text theme={null}
estimatedTokens = durationSeconds × 10,000
preConsumeQuota = estimatedTokens / 1,000,000
                 × matchedVideoPricePerMillion
                 × QuotaPerUnit
                 × groupRatio
```

例如，时长 5 秒、480P、无视频输入、单价 46 时，预估 Token 数约为 `50,000`，预扣额度约为：

```text theme={null}
50,000 / 1,000,000 × 46 × 500,000 = 1,150,000 quota
```

预扣不是最终费用：

* 实际 Token 少于预估值时，差额会在结算时退回；
* 实际 Token 多于预估值时，结算时会补扣差额；
* 任务失败时，本站按异步任务退款流程处理已预留额度；
* 上游没有返回有效 Token 时，系统无法进行精确 Token 重算，可能保留预扣结果，具体以消费日志为准。

因此建议始终显式传入 `duration` 和 `resolution`，这样预扣估算会更接近真实任务。

### 6.5 哪些数据是最终计费依据

提交时的请求字段用于预扣估算，任务完成时的上游结果用于最终结算：

| 阶段   | 使用的数据                                                              |
| ---- | ------------------------------------------------------------------ |
| 提交预扣 | 请求中的 `duration`、`metadata.resolution`、`metadata.content` 中的视频输入标记。 |
| 最终结算 | 上游返回的 `usage.total_tokens`、实际 `resolution`，以及提交时保存的视频输入判断。         |
| 消费日志 | 任务状态、实际 Token、单价、分辨率、时长、FPS 和视频输入标记。                               |

如果请求写的是 `720P`，但上游最终返回 `1080P`，最终结算会优先使用上游返回的实际分辨率。

## 7. 完整调用示例

### 示例一：无参考视频的文生视频

```bash theme={null}
curl -X POST "https://teio.me/v1/video/generations" \
  -H "Authorization: Bearer $NEW_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao-seedance-2-0-260128",
    "prompt": "一辆复古电车穿过雨后的上海街道，霓虹倒影，镜头平稳跟拍",
    "duration": 5,
    "metadata": {
      "resolution": "480P",
      "ratio": "16:9",
      "generate_audio": true,
      "watermark": false
    }
  }'
```

这个请求会按“不含视频输入”方向进行预扣和结算。它没有 `video_url`，因此不会触发含视频输入价格。

### 示例二：包含参考视频和参考图片

```bash theme={null}
curl -X POST "https://teio.me/v1/video/generations" \
  -H "Authorization: Bearer $NEW_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao-seedance-2-0-260128",
    "prompt": "参考视频的运镜节奏，将画面风格转换为水彩动画，保持参考图片中的主体外观",
    "duration": 8,
    "metadata": {
      "resolution": "1080P",
      "ratio": "9:16",
      "generate_audio": true,
      "content": [
        {
          "type": "image_url",
          "image_url": {
            "url": "https://cdn.example.com/character.jpg"
          },
          "role": "reference_image"
        },
        {
          "type": "video_url",
          "video_url": {
            "url": "https://cdn.example.com/motion.mp4"
          },
          "role": "reference_video"
        }
      ]
    }
  }'
```

因为 `metadata.content` 中包含 `type: "video_url"`，本站会将本次任务识别为“含视频输入”。在当前默认配置下，`1080P` 的含视频输入单价是 `31 / 百万 Token`。

### 示例三：轮询脚本

下面示例使用 `jq` 读取任务 ID 和状态：

```bash theme={null}
submit_response=$(curl -sS -X POST "https://teio.me/v1/video/generations" \
  -H "Authorization: Bearer $NEW_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao-seedance-2-0-fast-260128",
    "prompt": "海浪拍打黑色礁石，慢动作，电影感",
    "duration": 5,
    "metadata": {
      "resolution": "720P",
      "ratio": "16:9"
    }
  }')

task_id=$(printf '%s' "$submit_response" | jq -r '.task_id // .id')

if [ -z "$task_id" ] || [ "$task_id" = "null" ]; then
  printf 'submit failed: %s\n' "$submit_response" >&2
  exit 1
fi

for attempt in $(seq 1 60); do
  task_response=$(curl -sS "https://teio.me/v1/video/generations/$task_id" \
    -H "Authorization: Bearer $NEW_API_TOKEN")

  status=$(printf '%s' "$task_response" | jq -r '.data.status // empty')
  printf 'attempt=%s status=%s\n' "$attempt" "$status"

  case "$status" in
    SUCCESS)
      printf '%s\n' "$task_response" | jq -r '.data.result_url // .data.data.content.video_url // empty'
      break
      ;;
    FAILURE)
      printf '%s\n' "$task_response" | jq -r '.data.fail_reason // "task failed"' >&2
      exit 1
      ;;
  esac

  sleep 5
done
```

## 8. 常见问题

### Q1：为什么不能直接调用 `/v1/responses`？

`/v1/responses` 会进入对话 Responses 处理流程，而 Seedance 需要提交异步视频任务、保存任务状态、轮询上游和结算视频 Token。两者的请求体、上游 URL、响应结构和计费生命周期都不同。

### Q2：把视频 URL 放到 `image` 里可以享受含视频输入价格吗？

不可以。`image` 和 `images` 会被识别为图片输入。要触发含视频输入判断，应在 `metadata.content` 中使用 `type: "video_url"`。

### Q3：只填写 `metadata.resolution`，不填写 `duration` 可以吗？

可以，但不建议。缺少时长时，预扣估算默认按 5 秒处理；上游实际任务可能有自己的默认时长或直接拒绝请求。为了让预扣更准确，建议显式填写 `duration`。

### Q4：请求中写了 `720P`，为什么最后价格不是 720P 的价格？

最终结算以任务完成后上游返回的实际 `resolution` 为准。如果上游返回了其他分辨率，或者没有返回可识别的分辨率，系统会按实际可匹配的价格回退规则处理。

### Q5：为什么提交成功后余额马上减少？

这是异步任务的预扣。任务完成后系统会读取上游 `usage.total_tokens`，再进行差额结算；任务失败则按失败退款流程处理。提交时看到的扣减不一定是最终费用。

### Q6：返回“余额不足”，但我估计的最终费用并不高？

预扣需要先覆盖一笔基于时长、分辨率和视频输入的估算额度。请检查：

* 是否填写了过大的 `duration`；
* 是否选择了更高价格的输出分辨率；
* 是否包含了参考视频；
* 当前用户分组是否有额外倍率；
* 账户或 Token 额度是否足够支付预扣。

### Q7：任务一直处于 `QUEUED` 或 `IN_PROGRESS` 怎么办？

先确认轮询 URL 使用的是本站返回的公开 `task_id`，再按 2 至 5 秒间隔轮询。长时间没有变化时，查看本站任务日志和上游渠道状态，不要通过重复提交来“重试”同一个任务，以免产生多个任务和多笔预扣。

## 10. 接入检查清单

上线前建议逐项确认：

* [ ] 使用 `/v1/video/generations`，没有把 Seedance 请求发到 `/v1/responses`；
* [ ] `model` 和 `prompt` 位于顶层；
* [ ] 参考图片、视频、音频位于 `metadata.content`；
* [ ] 参考视频项使用 `type: "video_url"`；
* [ ] 已显式填写 `duration` 和 `metadata.resolution`；
* [ ] 轮询使用提交响应中的公开 `task_id`；
* [ ] 只在 `SUCCESS` 状态读取 `result_url`；
* [ ] 已处理 `FAILURE`、超时、余额不足和上游参数错误；
* [ ] 已记录任务 ID，便于查询消费日志和排查计费差异；
* [ ] 生产环境使用稳定、可被上游访问的媒体 URL。
