# Vidu 视频生成
> 参考图生视频为主，参考图最多 7 张
> 首帧生视频可选，提示词可省略由模型按首帧补全
> Q4 预览版支持最高 4K 与参考音频
`POST /v1/videos`
## 认证
- `Authorization` (string / 必填) — 所有接口均使用 Bearer Token 进行认证。 获取 API Key：[访问控制台](https://api.oairoute.com/keys) 创建。 请求时在请求头中添加： ```http Authorization: Bearer YOUR_OAIRoute_KEY ```
## 请求参数
> **Note:** 
> 提交成功只返回任务 ID，不含视频本身。拿成片用 `task_id` 轮询[获取任务状态](../tasks/status.html)，成片地址在 `result.videos[0].url`，该地址约 24 小时后过期，请及时转存。
- `model` (string / 必填) — 模型 ID，取值见下方模型列表。必须完全匹配，全小写。
- `prompt` (string / 条件必填) — 画面描述。参考生视频必填；图生视频可省略，此时由模型根据首帧自行生成内容。 注意描述动作与镜头，外观与风格由参考图决定。
- `image_urls` (string[] / 条件必填) — 参考图或首帧，公网地址或 Base64 data URI。 图生视频传且只传 1 张；参考生视频 1 到 15 张。
- `image_with_roles` (object[] / 可选) — 带角色的图片数组，每项含 `url` 与 `role`。 `role` 取值 `first_frame`、`reference_image`（别名 `reference`）。`last_frame` 与其他值返回 400。
- `first_frame_image` (string / 可选) — 首帧图片，仅图生视频可用。不能与其他图片或音频混用。
- `audio_urls` (string[] / 可选) — 参考音频，仅参考生视频可用。MP3，每段 3 到 12 秒，单段不超过 50MB，合计不超过 3 段。
- `audio_url` (string / 可选) — 单段参考音频，约束与 `audio_urls` 相同。
- `aspect_ratio` (string / 可选) — 输出画幅，取值 `16:9`、`9:16`、`4:3`、`3:4`、`1:1`，默认 `16:9`。 仅参考生视频生效，图生视频会忽略。别名 `size`。
- `duration` (integer / 可选) — 时长，单位秒，默认 `5`。 `viduq3`：3 到 16；`viduq3-mix`：1 到 16；`viduq4-preview`：3 到 16，不支持 1 到 2 秒。
- `resolution` (string / 可选) — 输出分辨率，默认 `720p`。 `viduq3`：`540p`、`720p`、`1080p`；`viduq3-mix`：`720p`、`1080p`；`viduq4-preview`：`540p` 到 `4K`。
- `audio` (boolean / 可选) — 是否输出音轨，默认 `true`。开关不影响计费。
- `seed` (integer / 可选) — 随机种子，省略或传 `0` 表示随机。
## 模式判定
只有一张首帧图，或只有一张 `role` 为 `first_frame` 的图，走图生视频。
只有一张不带角色也没有参考音频的图，同样按图生视频处理。
图片里出现 `reference_image` 角色，或者 2 到 15 张图且没有显式首帧，走参考生视频。
参考音频加 1 到 15 张图、没有显式首帧，也走参考生视频。
显式首帧与其他图片、参考角色或音频混用，提交阶段返回 400，不创建任务也不扣费。
## 支持的模型列表
| 模型 ID | 定位 |
|---|---|
| `viduq4-preview` | 预览版旗舰，最高 4K，支持参考音频，必须显式传 `model` |
| `viduq3-mix` | 画质最高，支持 1 秒短片，最高 1080p |
| `viduq3` | 日常首选，镜头切换更聪明，支持 540p 到 1080p |
| `viduq3-pro` | v3 的专业版，适合首尾帧与短片段 |
## 使用限制
- 参考图合计 1 到 15 张，单张不超过 50MB，最短边至少 128 像素，宽高比 1:4 到 4:1
- Base64 时整个请求体不超过 20MB，大图建议用公网地址
- `viduq3-mix` 不接受 540p
- `viduq4-preview` 不接受 1 到 2 秒
- 成片链接 24 小时后过期
## 响应
提交成功返回统一的受理结构：
```json
{
  "code": 200,
  "data": [
    {
      "status": "submitted",
      "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K"
    }
  ]
}
```
- `code` (integer / 总是返回) — 状态码，`200` 表示任务已受理。
- `data` (array / 总是返回) — 本次提交的任务列表，逐项提交时按顺序排列。
- `data[].status` (string / 总是返回) — 受理状态，提交成功时为 `submitted`。
- `data[].task_id` (string / 总是返回) — 任务 ID，用它轮询结果。
## 错误
| HTTP | type | 说明 |
|---|---|---|
| 400 | invalid_request_error | 请求参数无效，或参数组合冲突 |
| 401 | authentication_error | 身份验证失败，需检查 API Key |
| 402 | payment_required | 账户余额不足，需先充值 |
| 429 | rate_limit_error | 调用频率过高，稍后重试 |
参数错误在提交阶段同步返回，不创建任务、不扣费。
更多状态码与重试建议见[错误码与限流](../../support/errors.html)，常见报错的排查步骤见[常见问题](../../support/faq.html)。
## 查询任务
`GET /v1/tasks/{task_id}` 返回任务进度与结果，`status` 为 `completed` 时成片地址在 `result.videos[0].url`，元素带 `expires_at` 过期时间戳。
建议每 5 到 10 秒轮询一次，客户端总超时设为 10 到 15 分钟。`status` 取值 `pending`、`processing`、`completed`、`failed`、`cancelled`，以状态判定完成，不要依赖 `progress`。
失败任务自动退回费用，`error.message` 给出原因。
**参考生视频{Reference to video}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/videos' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "viduq4-preview",
  "prompt": "参考图中的角色走过赛博朋克霓虹街道，镜头横向跟拍",
  "image_urls": [
    "https://example.com/character-1.png",
    "https://example.com/character-2.png"
  ],
  "duration": 8,
  "resolution": "1080p",
  "aspect_ratio": "16:9"
}'
```
**参考生视频{Reference to video}::Python**
```
import requests
url = "https://api.oairoute.com/v1/videos"
headers = {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
}
payload = {
  "model": "viduq4-preview",
  "prompt": "参考图中的角色走过赛博朋克霓虹街道，镜头横向跟拍",
  "image_urls": [
    "https://example.com/character-1.png",
    "https://example.com/character-2.png"
  ],
  "duration": 8,
  "resolution": "1080p",
  "aspect_ratio": "16:9"
}
res = requests.post(url, headers=headers, json=payload)
print(res.json())
```
**参考生视频{Reference to video}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/v1/videos", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "model": "viduq4-preview",
  "prompt": "参考图中的角色走过赛博朋克霓虹街道，镜头横向跟拍",
  "image_urls": [
    "https://example.com/character-1.png",
    "https://example.com/character-2.png"
  ],
  "duration": 8,
  "resolution": "1080p",
  "aspect_ratio": "16:9"
}),
});
console.log(await res.json());
```
**200 参考生视频{Reference to video}**
```
{
  "code": 200,
  "data": [
    {
      "status": "submitted",
      "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K"
    }
  ]
}
```
**首帧生视频{First frame to video}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/videos' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "viduq3",
  "image_urls": [
    "https://example.com/scene.png"
  ],
  "duration": 5,
  "resolution": "720p"
}'
```
**首帧生视频{First frame to video}::Python**
```
import requests
url = "https://api.oairoute.com/v1/videos"
headers = {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
}
payload = {
  "model": "viduq3",
  "image_urls": [
    "https://example.com/scene.png"
  ],
  "duration": 5,
  "resolution": "720p"
}
res = requests.post(url, headers=headers, json=payload)
print(res.json())
```
**首帧生视频{First frame to video}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/v1/videos", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "model": "viduq3",
  "image_urls": [
    "https://example.com/scene.png"
  ],
  "duration": 5,
  "resolution": "720p"
}),
});
console.log(await res.json());
```
**200 首帧生视频{First frame to video}**
```
{
  "code": 200,
  "data": [
    {
      "status": "submitted",
      "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K"
    }
  ]
}
```
**参考音频{Reference audio}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/videos' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "viduq4-preview",
  "prompt": "人物随参考音频的节奏舞动",
  "image_urls": [
    "https://example.com/dancer.png"
  ],
  "audio_urls": [
    "https://example.com/beat.mp3"
  ],
  "duration": 8,
  "resolution": "1080p"
}'
```
**参考音频{Reference audio}::Python**
```
import requests
url = "https://api.oairoute.com/v1/videos"
headers = {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
}
payload = {
  "model": "viduq4-preview",
  "prompt": "人物随参考音频的节奏舞动",
  "image_urls": [
    "https://example.com/dancer.png"
  ],
  "audio_urls": [
    "https://example.com/beat.mp3"
  ],
  "duration": 8,
  "resolution": "1080p"
}
res = requests.post(url, headers=headers, json=payload)
print(res.json())
```
**参考音频{Reference audio}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/v1/videos", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "model": "viduq4-preview",
  "prompt": "人物随参考音频的节奏舞动",
  "image_urls": [
    "https://example.com/dancer.png"
  ],
  "audio_urls": [
    "https://example.com/beat.mp3"
  ],
  "duration": 8,
  "resolution": "1080p"
}),
});
console.log(await res.json());
```
**200 参考音频{Reference audio}**
```
{
  "code": 200,
  "data": [
    {
      "status": "submitted",
      "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K"
    }
  ]
}
```
**4K 输出{4K output}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/videos' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "viduq4-preview",
  "prompt": "海岸线航拍，镜头缓慢前推",
  "image_urls": [
    "https://example.com/coast.png"
  ],
  "duration": 8,
  "resolution": "4K"
}'
```
**4K 输出{4K output}::Python**
```
import requests
url = "https://api.oairoute.com/v1/videos"
headers = {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
}
payload = {
  "model": "viduq4-preview",
  "prompt": "海岸线航拍，镜头缓慢前推",
  "image_urls": [
    "https://example.com/coast.png"
  ],
  "duration": 8,
  "resolution": "4K"
}
res = requests.post(url, headers=headers, json=payload)
print(res.json())
```
**4K 输出{4K output}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/v1/videos", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "model": "viduq4-preview",
  "prompt": "海岸线航拍，镜头缓慢前推",
  "image_urls": [
    "https://example.com/coast.png"
  ],
  "duration": 8,
  "resolution": "4K"
}),
});
console.log(await res.json());
```
**200 4K 输出{4K output}**
```
{
  "code": 200,
  "data": [
    {
      "status": "submitted",
      "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K"
    }
  ]
}
```
