# 可灵 3.0 视频生成 API

> 可灵 3.0 路径式任务接口：文生视频、图生视频、Omni 多模态、动作控制、数字人生成与批量任务查询

可灵 3.0 采用**异步任务**模式，接口对标可灵官方 3.0 路径式 API：先提交任务拿到 `id`，再轮询 `GET /tasks` 获取成片。模型名写在 URL 路径里（`/text-to-video/kling-3.0`），请求体用 `settings` / `options` / `contents` 三个字段组织参数。

<Warning>
**接入前请注意以下要点：**

1. Base URL 为 `https://api.looprouter.com`，端点是 `/text-to-video/{model}` 等；路径可**选**加 `/v1` 前缀（如 `/v1/text-to-video/{model}`），带与不带行为完全一致，方便可灵 SDK 直接接入。
2. 鉴权用 LoopRouter 令牌：`Authorization: Bearer sk-...`。
3. `model` 写在路径中：`kling-3.0` / `kling-3.0-turbo` 走文生 / 图生端点，`kling-3.0-omni` 走 `/omni-video`。
4. `settings.resolution` 取 `720p` / `1080p` / `4k`；`settings.duration` 为整数秒。
5. 成功状态是 `succeeded`；成片 `outputs[].url` 为限时链接，请尽快转存。
6. 回调（`options.callback_url`）当前**不投递**，请通过轮询 `GET /tasks` 获取结果。
</Warning>

## 创建视频任务

三个提交端点共用同一套请求体结构（`prompt` + `settings` + `options` + `contents`），仅 `contents` 的组合不同。

<CodeGroup>

```bash 文生视频（cURL）
curl -X POST "https://api.looprouter.com/text-to-video/kling-3.0" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY" \
  -d '{
    "prompt": "一只柯基犬在草地上奔跑，阳光明媚，慢镜头",
    "settings": {
      "resolution": "1080p",
      "aspect_ratio": "16:9",
      "duration": 5,
      "audio": "native",
      "multi_shot": true
    }
  }'

# 返回：{"code":0,"message":"SUCCEED","request_id":"...","data":{"id":"task_xxxx","status":"submitted","create_time":1781080778802,"update_time":1781080778802}}
```

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

BASE = "https://api.looprouter.com"
HEADERS = {"Authorization": "Bearer sk-你的APIKey"}

# 1. 创建任务
resp = requests.post(
    f"{BASE}/text-to-video/kling-3.0",
    headers=HEADERS,
    json={
        "prompt": "一只柯基犬在草地上奔跑，阳光明媚，慢镜头",
        "settings": {
            "resolution": "1080p",
            "aspect_ratio": "16:9",
            "duration": 5,
            "audio": "native",
        },
    },
)
resp.raise_for_status()
task_id = resp.json()["data"]["id"]
print("任务已创建:", task_id)

# 2. 轮询任务状态（建议 10 秒一次）
while True:
    data = requests.get(
        f"{BASE}/tasks",
        headers=HEADERS,
        params={"task_ids": task_id},
    ).json()["data"]
    task = data[0]
    status = task["status"]
    print("当前状态:", status)
    if status in ("succeeded", "failed"):
        break
    time.sleep(10)

# 3. 下载成片（下载时不要携带 Authorization 头）
if status == "succeeded":
    video_url = task["outputs"][0]["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_id)
```

```json 图生视频（首帧 / 首尾帧）
// POST /image-to-video/kling-3.0
// 首帧：contents 放 1 张 first_frame；首尾帧：再加 1 张 last_frame
{
  "prompt": "镜头缓缓推进，人物转身微笑，从清晨过渡到黄昏",
  "settings": {
    "resolution": "1080p",
    "duration": 5,
    "audio": "native"
  },
  "contents": [
    { "type": "first_frame", "url": "https://example.com/first.jpg" },
    { "type": "last_frame", "url": "https://example.com/last.jpg" }
  ]
}
```

```json Omni 多模态（参考图 + 参考视频）
// POST /omni-video/kling-3.0-omni
// contents 里放 refer_image / feature_video / base_video / element 等素材，
// 网关按顺序自动把素材绑定进提示词，无需手写占位符。
{
  "prompt": "让参考图中的角色在城市夜景中行走，参考该视频的运镜与节奏",
  "settings": {
    "resolution": "1080p",
    "aspect_ratio": "16:9",
    "duration": 5,
    "audio": "original"
  },
  "options": {
    "external_task_id": "my-biz-001"
  },
  "contents": [
    { "type": "refer_image", "url": "https://example.com/character.jpg" },
    { "type": "feature_video", "url": "https://example.com/motion.mp4" }
  ]
}
```

</CodeGroup>

### 请求参数速查

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `prompt` | string | 条件 | 主提示词。文生视频必填；也可作为 `contents` 里的 `type=prompt` 项提供 |
| `settings` | object | 否 | 生成设置，见 [settings 字段](#settings-字段) |
| `options` | object | 否 | 任务选项，见 [options 字段](#options-字段) |
| `contents` | array | 条件 | 素材数组：图生视频与 Omni 必填，见 [contents 数组](#contents-数组) |

### settings 字段

| 字段 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `resolution` | string | `720p` | `720p` / `1080p` / `4k`（Turbo 通常至 `1080p`） |
| `aspect_ratio` | string | `16:9` | `16:9` / `9:16` / `1:1` |
| `duration` | int | 模型默认 | 输出时长（整数秒），如 `5` / `10` |
| `audio` | string | `off` | `native` 生成配套音频；`original` 保留参考视频原声（仅 Omni 的 `feature_video`）；`off` 静音 |
| `multi_shot` | bool | `true` | 多镜头分镜叙事开关 |

<Info>
仅传入的字段会覆盖网关默认值，省略的字段沿用模型档位默认。`multi_shot` 用指针区分「未设置」与「显式 `false`」，需要关闭多镜头时请显式传 `false`。
</Info>

### options 字段

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `external_task_id` | string | 否 | 业务自定义 ID，回显在任务 `external_id`，可用 `GET /tasks?external_task_ids=` 反查 |
| `watermark_info.enabled` | bool | 否 | 是否叠加水印 |
| `callback_url` | string | 否 | 预留字段，**当前不投递回调**，请改用轮询 `GET /tasks` |

### contents 数组

每个元素由 `type` 决定读取哪些字段。图生视频用 `first_frame` / `last_frame`；Omni 可组合多种素材：

| type | 字段 | 适用端点 | 说明 |
| --- | --- | --- | --- |
| `prompt` | `text` | 全部 | 提示词，等价于顶层 `prompt` |
| `first_frame` | `url` | 图生 / Omni | 首帧图 |
| `last_frame` | `url` | 图生 / Omni | 尾帧图 |
| `refer_image` | `url` | Omni | 参考图；网关自动为其创建主体元素 |
| `feature_video` | `url` | Omni | 参考视频（运镜 / 风格；`audio=original` 时保留其原声） |
| `base_video` | `url` | Omni | 基准视频，在其基础上续写 / 编辑 |
| `element` | `element_id` | Omni | 引用既有主体，传数字 `element_id` |

<Note>
Omni 生成时，网关会按 `contents` 中素材出现的顺序把它们绑定进提示词，你只需在 `prompt` 中自然描述即可，无需手动书写素材占位符。
</Note>

<Tip>
`element` 引用的 `element_id` 来自[自定义主体](/api-capabilities/kling/custom-elements)（主体管理）：用参考图 / 参考视频**显式创建一个可复用主体**，查询成功后拿到数字 `element_id`，即可让同一主体在多次生成中保持一致。这与 `refer_image` 传图后由网关**临时**创建主体不同——后者一次性，前者可复用。
</Tip>

### 三类生成端点

| 端点 | 模型 | contents 组合 |
| --- | --- | --- |
| `POST /text-to-video/{model}` | `kling-3.0` / `kling-3.0-turbo` | 仅 `prompt` + `settings`（可省略 `contents`） |
| `POST /image-to-video/{model}` | `kling-3.0` / `kling-3.0-turbo` | `prompt` + `first_frame`（可加 `last_frame`） |
| `POST /omni-video/{model}` | `kling-3.0-omni` | `prompt` + 若干 Omni 素材（`refer_image` / `feature_video` / `base_video` / `element`） |

提交成功返回统一的 ack 信封，`data.id` 为网关任务 ID（后续查询用它）：

```json
{
  "code": 0,
  "message": "SUCCEED",
  "request_id": "0217852290155100a2c883cf675b9804d",
  "data": {
    "id": "task_xxxx",
    "status": "submitted",
    "create_time": 1781080778802,
    "update_time": 1781080778802,
    "external_id": "my-biz-001"
  }
}
```

## 动作控制

`POST /motion-control/{model}` · 模型 `kling-3.0-motion-control`

动作控制（Motion Control）用一段**参考视频**驱动图片中的角色 / 主体做出对应动作。它是**专用端点**，计费模型由端点自动绑定（路径里的 `{model}` 仅作占位，写 `kling-3.0` 或 `kling-3.0-motion-control` 均可）。请求体支持两种形态：**官方 `contents` + `settings`**（推荐，与可灵官方一致），或**扁平结构**（顶层直接放 `image_url` / `video_url` / `mode` 等，作兼容别名，走 `POST /videos/motion-control`）。两者并存时以 `contents` / `settings` 优先。

<CodeGroup>

```bash 官方形态（contents + settings）
curl -X POST "https://api.looprouter.com/motion-control/kling-3.0" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY" \
  -d '{
    "contents": [
      { "type": "image", "url": "https://example.com/char.png" },
      { "type": "video", "url": "https://example.com/drive.mp4" },
      { "type": "prompt", "text": "the character dances energetically" }
    ],
    "settings": {
      "character_orientation": "video",
      "audio": "original",
      "resolution": "720p"
    }
  }'
```

```bash 扁平形态（兼容别名）
curl -X POST "https://api.looprouter.com/videos/motion-control" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY" \
  -d '{
    "prompt": "the character dances energetically",
    "image_url": "https://example.com/char.png",
    "video_url": "https://example.com/drive.mp4",
    "mode": "std",
    "character_orientation": "video",
    "keep_original_sound": "yes",
    "watermark_info": { "enabled": false }
  }'
```

</CodeGroup>

**官方形态** —— `contents[]` 按内容顺序给出角色图片、参考视频与描述，`settings` 控制朝向、原声与分辨率：

| `contents[].type` | 字段 | 说明 |
| --- | --- | --- |
| `image`（或 `refer_image` / `first_frame`） | `url` | 被驱动的角色 / 主体图片 |
| `video`（或 `feature_video` / `base_video`） | `url` | 提供动作的参考视频 |
| `prompt` | `text` | 补充描述 |
| `element` | `element_id` | 引用既有主体 |

| `settings` 字段 | 取值 | 说明 |
| --- | --- | --- |
| `character_orientation` | `image` / `video` | 动作朝向对齐基准 |
| `audio` | `original` / `native` / `off` | `original` / `native` 保留参考视频原声，`off` 静音 |
| `resolution` | `720p` / `1080p` | 决定计费档位（`720p`→`std`、`1080p`→`pro`） |

**扁平形态**（兼容别名，`POST /videos/motion-control`）：

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `image_url` | string | 是 | 被驱动的角色 / 主体图片 URL |
| `video_url` | string | 是 | 提供动作的参考视频 URL |
| `mode` | string | 是 | `std`（→ `720p` 档）/ `pro`（→ `1080p` 档），决定计费档位 |
| `character_orientation` | string | 是 | 动作朝向对齐基准：`image`（对齐图片）/ `video`（对齐参考视频） |
| `prompt` | string | 否 | 补充描述 |
| `keep_original_sound` | string | 否 | 是否保留参考视频原声：`"yes"` / `"no"`（字符串，非布尔） |
| `watermark_info.enabled` | bool | 否 | 是否叠加水印 |

<Info>
输出时长由参考视频决定、提交时未知，网关按**最大计费时长 30 秒**预扣，任务完成后按实际时长回收多退少补（见[计费规则](/api-capabilities/kling/overview#模型定价)），因此提交时请保证余额充足。上游以 `model_name: "kling-v3"` 提交。
</Info>

动作控制**是视频任务**，提交成功返回与文 / 图 / Omni 一致的 ack 信封（`data.id` 为网关任务 ID、`data.status`），后续**统一走 `GET /tasks` 查询**：

```json
{
  "code": 0,
  "message": "SUCCEED",
  "request_id": "202608101345034646613008268d9d64xm9uHKV",
  "data": {
    "id": "task_xxxx",
    "status": "submitted",
    "create_time": 1786369503495,
    "update_time": 1786369503495
  }
}
```

## 数字人

`POST /videos/avatar/image2video` · 模型 `kling-3.0-avatar`

数字人（Avatar）用一段**音频**驱动人像图片开口说话（口型对齐）。同为**专用端点**、请求体**扁平结构**（不使用 `settings` / `contents`），计费模型由端点自动绑定。

```bash cURL
curl -X POST "https://api.looprouter.com/videos/avatar/image2video" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY" \
  -d '{
    "image": "https://example.com/face.png",
    "audio_id": "voice-abc-123",
    "prompt": "news anchor reading headlines",
    "mode": "std",
    "watermark_info": { "enabled": false }
  }'
```

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `image` | string | 是 | 被驱动的人像图片 URL |
| `audio_id` | string | 条件 | 驱动音频 ID；可直接填[声音复刻](/api-capabilities/kling/voice-cloning)产出的 `voice_id`。与 `sound_file` 二选一 |
| `sound_file` | string | 条件 | 直接提供驱动音频文件 URL，与 `audio_id` 二选一 |
| `mode` | string | 否 | `std`（→ `720p` 档）/ `pro`（→ `1080p` 档），决定计费档位 |
| `prompt` | string | 否 | 补充描述 |
| `watermark_info.enabled` | bool | 否 | 是否叠加水印 |

<Info>
输出时长跟随驱动音频（约 2–300 秒）、提交时未知，网关按**最大计费时长 300 秒**预扣，完成后按实际时长回收多退少补。`pro`（1080p）单价更高，请预留足够余额。上游数字人请求体**不带 `model_name` 字段**。
</Info>

数字人的提交与查询**不走视频任务那套 ack / `GET /tasks`**，而是**专属信封**：提交返回 `data.task_id` / `data.task_status`，成功态是 **`succeed`**（注意——不是视频端点的 `succeeded`），并用**专属查询端点**拉取结果。提交响应：

```json
{
  "code": 0,
  "message": "SUCCEED",
  "request_id": "202608101348177602932008268d9d6f5NscS8V",
  "data": {
    "task_id": "task_xxxx",
    "task_status": "submitted",
    "task_status_msg": "",
    "created_at": 1786369697787,
    "updated_at": 1786369697787
  }
}
```

用专属端点查询（**不要**用 `GET /tasks`）：

`GET /videos/avatar/image2video/{task_id}`

```bash cURL
curl "https://api.looprouter.com/videos/avatar/image2video/task_xxxx" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY"
```

成功时 `task_status` 为 `succeed`，成片在 `data.task_result.videos[]`（`id` / `url` / `duration`）：

```json
{
  "code": 0,
  "message": "SUCCEED",
  "request_id": "202608101351020000000008268d9d70abc",
  "data": {
    "task_id": "task_xxxx",
    "task_status": "succeed",
    "task_status_msg": "",
    "task_result": {
      "videos": [
        {
          "id": "task_xxxx",
          "url": "https://api.looprouter.com/v1/videos/task_xxxx/content",
          "duration": "8"
        }
      ]
    },
    "created_at": 1786369697787,
    "updated_at": 1786369730000
  }
}
```

<Note>
声音复刻（`kling-3.0-voice`）是**非视频**的独立任务，请求体、计费与查询方式都不同（同样是 `task_id` / `succeed` 专属信封 + 专属查询端点），详见[声音复刻 API](/api-capabilities/kling/voice-cloning)。
</Note>

## 查询任务

`GET /tasks`

批量查询任务，`task_ids` 与 `external_task_ids` **二选一**（一次只认一种，`task_ids` 优先），均支持逗号分隔批量。文生 / 图生 / Omni / **动作控制**四类视频任务都用它查询，任务状态机：`submitted → processing → succeeded / failed`。**数字人**与**声音复刻**不在此列 —— 它们各有专属查询端点（`GET /videos/avatar/image2video/{task_id}`、`GET /general/custom-voices/{task_id}`），成功态是 `succeed`。

| 查询参数 | 说明 |
| --- | --- |
| `task_ids` | 网关任务 ID 列表，逗号分隔，如 `task_a,task_b` |
| `external_task_ids` | 业务自定义 ID 列表（`options.external_task_id`），逗号分隔 |

```bash 按任务 ID 查询
curl "https://api.looprouter.com/tasks?task_ids=task_xxxx,task_yyyy" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY"
```

```bash 按业务 ID 查询
curl "https://api.looprouter.com/tasks?external_task_ids=my-biz-001" \
  -H "Authorization: Bearer $LOOPROUTER_API_KEY"
```

响应 `data` **恒为数组**，每个元素结构如下：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | string | 任务 ID |
| `status` | string | `submitted` / `processing` / `succeeded` / `failed` |
| `create_time` / `update_time` | int | Unix 毫秒时间戳 |
| `external_id` | string | 回显 `options.external_task_id`（若有） |
| `outputs` | array | 成片产物数组，成功时含 `id` / `url` / `duration` |

`outputs[]` 元素：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | string | 产物 ID（与任务 `id` 一致） |
| `url` | string | 成片下载地址（限时链接） |
| `duration` | string | 成片时长（秒） |

成功响应示例：

```json
{
  "code": 0,
  "message": "SUCCEED",
  "request_id": "0217852290155100a2c883cf675b9804d",
  "data": [
    {
      "id": "task_xxxx",
      "status": "succeeded",
      "create_time": 1781080778802,
      "update_time": 1781080794151,
      "external_id": "my-biz-001",
      "outputs": [
        {
          "id": "task_xxxx",
          "url": "https://api.looprouter.com/v1/videos/task_xxxx/content",
          "duration": "5"
        }
      ]
    }
  ]
}
```

处理中 / 失败示例（`outputs` 为空数组）：

```json
{
  "code": 0,
  "message": "SUCCEED",
  "request_id": "0217852290155100a2c883cf675b9804d",
  "data": [
    { "id": "task_yyyy", "status": "processing", "create_time": 1781080778802, "update_time": 1781080780000, "outputs": [] },
    { "id": "task_zzzz", "status": "failed", "create_time": 1781080778802, "update_time": 1781080790000, "outputs": [] }
  ]
}
```

<Warning>
`outputs[].url` 为**限时下载链接**，请及时转存；下载时请求中**不要**携带 `Authorization` 头。
</Warning>

## 错误响应

参数错误、鉴权失败或上游异常时返回错误信封：

| HTTP 状态码 | 常见原因 |
| --- | --- |
| 400 | 参数错误，如缺少 `prompt`、`resolution` 取值非法、`task_ids` 与 `external_task_ids` 均缺失 |
| 401 | API Key 缺失或无效 |
| 429 | 触发限流，请稍后重试 |
| 500 | 服务端异常，建议指数退避后重试 |

<Info>
429 与 5xx 建议指数退避重试（2s → 4s → 8s）。任务本身的失败不体现为 HTTP 错误，而是查询时 `status` 为 `failed`。
</Info>

## 在线调试（试一试）

在 API 参考中可对每个端点直接发起真实请求：

<CardGroup cols={2}>
  <Card title="文生视频" icon="flask" href="/api-reference/kling/text-to-video">
    POST /text-to-video/{model}
  </Card>
  <Card title="图生视频" icon="flask" href="/api-reference/kling/image-to-video">
    POST /image-to-video/{model}
  </Card>
  <Card title="Omni 多模态生成" icon="flask" href="/api-reference/kling/omni-video">
    POST /omni-video/{model}
  </Card>
  <Card title="动作控制" icon="flask" href="/api-reference/kling/motion-control">
    POST /motion-control/{model}
  </Card>
  <Card title="数字人提交" icon="flask" href="/api-reference/kling/avatar">
    POST /videos/avatar/image2video
  </Card>
  <Card title="数字人查询" icon="flask" href="/api-reference/kling/get-avatar">
    GET /videos/avatar/image2video/{task_id}
  </Card>
  <Card title="任务查询" icon="flask" href="/api-reference/kling/list-tasks">
    GET /tasks
  </Card>
</CardGroup>

## 相关文档

<CardGroup cols={2}>
  <Card title="能力总览与定价" icon="circle-info" href="/api-capabilities/kling/overview">
    模型清单、技术规格、计费规则
  </Card>
  <Card title="快速开始" icon="rocket" href="/getting-started">
    三步跑通第一个任务
  </Card>
</CardGroup>
