# 视频生成 API

使用 POST /api/v1/videos 创建视频生成任务，并了解响应、积分与错误处理。

## 创建视频任务

`POST /api/v1/videos` 会先校验请求、扣除积分并把任务提交给提供方，然后才返回响应。视频随后异步生成：每 5–10 秒轮询一次 [`GET /api/v1/tasks/{taskId}`](https://viewmax.studio/zh/docs/api/tasks)，直到状态变为 `success`、`failed` 或 `canceled`。服务端没有超时限制，请自行设定截止时间。

```http
POST https://viewmax.studio/api/v1/videos
Authorization: Bearer sk-your-api-key
Content-Type: application/json
Idempotency-Key: kite-001
```

`Idempotency-Key` 可选，但建议始终发送；见[幂等](#幂等)。

## 请求体

| 字段         | 必填 | 类型     | 说明                                                                                                                        |
| ------------ | ---- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| `model`      | 是   | string   | `GET /api/v1/models` 返回的模型 `id`。已下线的模型（如 `sora-2`）不会列出，调用时返回 400                                   |
| `prompt`     | 是   | string   | 非空，首尾空白会被去掉。若目录给出 `max_prompt_length`，长度不得超过该字符数（目前只有 `minimax-h3`：7000）                 |
| `mode`       | 否   | string   | `text-to-video`、`image-to-video`、`video-to-video`、`frames-to-video` 或 `reference-to-video`；必须是该模型 `modes` 中的键 |
| `image_urls` | 否   | string[] | 提供方无需鉴权即可下载的 `http://` 或 `https://` 图片 URL。各模型和模式的数量见[输入限制](#输入限制)                        |
| `video_urls` | 否   | string[] | 一个 `http(s)` 源视频。`video-to-video` 必填；部分模型的 `reference-to-video` 可选                                          |
| `options`    | 否   | object   | 模型目录中列出的生成控制项                                                                                                  |

未传 `mode` 时：`image_urls` 非空则为 `image-to-video`；否则 `video_urls` 非空则为 `video-to-video`；否则为 `text-to-video`。`frames-to-video` 和 `reference-to-video` 必须显式传 `mode`。

### `options`

| 字段                            | 类型              | 说明                                                                                                                                                             |
| ------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `duration`                      | string 或 integer | `modes.<mode>.durations` 中的值；`"8s"`、`"8"` 与 `8` 等价。列表为空时不要传（Veo 3.1 系列）                                                                     |
| `resolution`                    | string            | `modes.<mode>.resolutions` 中的值，如 `480p`、`720p`、`1080p`、`4k`、`768P` 或 `2K`。匹配不区分大小写，但请按目录写法发送。列表为空时不要传（Kling 2.6、FLUX 3） |
| `aspect_ratio`                  | string            | `modes.<mode>.aspect_ratios` 中的值，大小写须完全一致（`Auto`，不是 `auto`）                                                                                     |
| `audio`                         | boolean           | 仅当 `modes.<mode>.audio_toggle` 为 `true` 时才能传 `true`；`false` 始终可用                                                                                     |
| `source_video_duration_seconds` | number            | `video_urls` 源视频的秒数。模式列出 `credits_per_second` 且传了 `video_urls` 时必填（Seedance 2.x、Seedance 2.5、MiniMax H3）                                    |

未传的 `duration`、`resolution` 和 `aspect_ratio` 会在计价前用 `GET /api/v1/models` 中的 `modes.<mode>.defaults` 补齐，补齐后的值也会发送给提供方。例如 `viewmax-c1` 的默认值是 `5s`、`768P` 和 `16:9`。部分模型在某些分辨率下可选时长更少（`runway` 在 `1080p` 下只支持 `5s`）。其他 `options` 键会原样转发给提供方，不做校验。

### 输入限制

以下数量不符合时，ViewMax 会在扣费前返回 400。`—` 表示该模型不提供此模式。

| 模型                    | text-to-video | image-to-video | frames-to-video | reference-to-video      | video-to-video        |
| ----------------------- | ------------- | -------------- | --------------- | ----------------------- | --------------------- |
| `viewmax-c1`            | 支持          | 1 张图         | 2 张图          | 1–9 张图                | —                     |
| `viewmax-turbo`         | 支持          | 1 张图         | 2 张图          | —                       | —                     |
| `seedance-2-5`          | 支持          | 1 张图         | 2 张图          | 1–3 张图                | 1 个视频 ¹            |
| `seedance-2-0`          | 支持          | 1–2 张图       | 2 张图          | 1–2 张图 + 0–1 个视频 ¹ | —                     |
| `seedance-2-0-fast`     | 支持          | 1–2 张图       | 2 张图          | 1–2 张图 + 0–1 个视频 ¹ | —                     |
| `seedance-2-mini`       | 支持          | 1–2 张图       | 2 张图          | 1–2 张图 + 0–1 个视频 ¹ | —                     |
| `seedance-1-5-pro`      | 支持          | 1 张图         | —               | —                       | —                     |
| `minimax-h3`            | 支持          | 1 张图         | 2 张图          | 1–4 张图 + 0–1 个视频 ¹ | 1 个视频 + 0–2 张图 ¹ |
| `veo-3-1`               | 支持          | 1 张图         | 2 张图          | 1–3 张图                | —                     |
| `veo-3-1-fast`          | 支持          | 1 张图         | 2 张图          | 1–3 张图                | —                     |
| `veo-3-1-lite`          | 支持          | 1 张图         | 2 张图          | 1–3 张图                | —                     |
| `gemini-omni`           | 支持          | 1 张图         | —               | —                       | 1 个视频 + 0–2 张图 ² |
| `gemini-omni-video`     | 支持          | 1 张图         | —               | —                       | 1 个视频 ³            |
| `gemini-omni-cheap`     | 支持          | 1–2 张图       | —               | —                       | —                     |
| `flux-3`                | 支持          | 1 张图         | 2–3 张图        | —                       | 1 个视频              |
| `kling-2-6`             | 支持          | 1 张图         | —               | —                       | —                     |
| `grok-imagine`          | 支持          | 1 张图         | —               | —                       | —                     |
| `grok-imagine-1-5`      | 支持          | 1 张图         | —               | —                       | —                     |
| `runway`                | 支持          | 1 张图         | —               | —                       | —                     |
| `p-video`               | 支持          | 1–2 张图       | —               | —                       | —                     |
| `seedence-1-0-pro`      | 支持          | 1 张图         | —               | —                       | —                     |
| `seedence-1-0-pro-fast` | —             | 1 张图         | —               | —                       | —                     |
| `seedence-1-0-lite`     | 支持          | 1 张图         | —               | —                       | —                     |

¹ 传视频时还需发送 `options.source_video_duration_seconds`。

² `gemini-omni` 只接受 10 秒及以内的源视频；更长的源视频会在提供方处失败（任务失败并退还积分）。

³ `gemini-omni-video` 接受最长 30 秒的源视频，并使用前 10 秒。

## 示例

```bash
curl -X POST https://viewmax.studio/api/v1/videos \
  -H "Authorization: Bearer $VIEWMAX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: kite-001" \
  -d '{
    "model": "viewmax-c1",
    "mode": "text-to-video",
    "prompt": "A paper kite crossing a bright summer sky",
    "options": { "duration": "5s", "resolution": "768P", "aspect_ratio": "16:9" }
  }'
```

该请求消耗 10 积分（每秒 2 积分 × 5 秒）；Ultra 用户在 ViewMax C1 额度内为 `0`。

## 成功响应

```json
{
  "code": 0,
  "message": "ok",
  "data": {
    "id": "3f1c9a2e-5b7d-4c1e-9a0f-2d6e8b4c7a10",
    "userId": "usr_123",
    "mediaType": "video",
    "model": "viewmax-c1/text-to-video",
    "prompt": "A paper kite crossing a bright summer sky",
    "options": "{\"duration\":5,\"resolution\":\"768P\",\"aspect_ratio\":\"16:9\",\"mode\":\"text-to-video\"}",
    "status": "pending",
    "createdAt": "2026-09-29T08:00:00.000Z",
    "updatedAt": "2026-09-29T08:00:01.000Z",
    "deletedAt": null,
    "taskId": "job_abc",
    "taskInfo": null,
    "taskResult": null,
    "taskUrls": [],
    "costCredits": 10,
    "scene": "text-to-video",
    "visibility": "user",
    "creditId": "cr_123",
    "waivedCredits": 0,
    "fairUseKey": null
  }
}
```

### 任务字段

所有创建端点和 `GET /api/v1/tasks/{taskId}` 都返回同一种任务对象。

| 字段                     | 说明                                                                                                                                            |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                     | 任务 ID，用它轮询 `GET /api/v1/tasks/{taskId}`                                                                                                  |
| `status`                 | `pending` 或 `processing`：继续轮询。`success`：读取 `taskUrls`。`failed` 或 `canceled`：停止轮询，积分已退还                                   |
| `taskUrls`               | 结果 URL，始终是数组；`success` 之前为空                                                                                                        |
| `costCredits`            | 实际扣除的积分；由套餐额度抵扣时为 `0`                                                                                                          |
| `waivedCredits`          | 套餐额度抵扣掉的原价，否则为 `0`                                                                                                                |
| `fairUseKey`             | 本任务占用的额度槽位，未占用时为 `null`                                                                                                         |
| `mediaType`、`scene`     | `video` 与所用模式                                                                                                                              |
| `model`                  | 实际执行任务的模型标识，可能与请求中的 `model` 不同                                                                                             |
| `options`                | 计价并提交时使用的选项（JSON 字符串），包含补齐的默认值和 `mode`                                                                                |
| `taskInfo`、`taskResult` | JSON 字符串。运行中或成功后保存的是任务诊断信息，结构不固定，不要依赖。`failed` 或 `canceled` 时两者都是 `{"errorCode","error","errorMessage"}` |

另外还会返回 `userId`、`taskId`（上游任务 ID）、`creditId`、`visibility`、`createdAt`、`updatedAt` 和 `deletedAt`。`errorCode` 取值为 `insufficient_credits`、`auth_required`、`rate_limited`、`request_cancelled`、`provider_unavailable`、`invalid_input`、`content_rejected`、`busy`、`duplicate_request` 或 `generic`；只有 `invalid_input` 时 `errorMessage` 才包含提供方给出的原因。

## 幂等

每次创建请求都发送 `Idempotency-Key` 请求头（1–200 个可见 ASCII 字符，不含空格）。重复使用同一个键会返回第一次请求创建的任务及其原始 `costCredits`，不会再次扣费。服务端不比较请求体；同一账号的所有创建端点共用这些键。

- 超时或连接中断后，用**同一个**键重试。
- 有意发起新的尝试时（例如任务 `failed`，或收到带 `error.task_id` 的 400），换用**新的**键；旧键会一直返回旧任务。
- 不带该请求头时，每次 POST 都会创建新任务并扣费。
- 键格式无效时返回 400 `Idempotency-Key must be 1-200 visible ASCII characters without spaces`。

## 积分与退款

- 任务创建时扣除积分。余额低于费用时返回 402，不创建任务。
- 以 `failed` 或 `canceled` 结束的任务会自动退还积分，占用的套餐额度也会归还。
- Ultra 上的 ViewMax C1 使用每日 300 秒输出时长的额度（按 UTC 日计算），与 ViewMax 网页和 MCP 共用。额度内 `costCredits` 为 `0`，`waivedCredits` 为原价，并写入 `fairUseKey`。请求时长超过剩余额度时按全价扣费。网页中其他视频模型的额度不适用于 API。

## 估算费用

没有费用预览端点。请根据 `GET /api/v1/models` 中的 `modes.<mode>`，用你发送的值或 `defaults` 计算：

| 目录字段                                             | 费用                                                                                                                 |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `credits[resolution][duration]`                      | 该组合的固定价格                                                                                                     |
| `credits[resolution].per_generation`                 | 每个视频的固定价格                                                                                                   |
| `credits[duration]["with-audio" \| "without-audio"]` | Kling 2.6，按 `audio` 选择                                                                                           |
| `credits_per_second[resolution]`                     | `ceil(单价 × 时长秒数)`                                                                                              |
| `credits_per_second_with_video_input[resolution]`    | 传了 `video_urls` 时使用。Seedance 2.0、2.0 Fast 和 2 Mini 按 `时长 + min(source_video_duration_seconds, 15)` 秒计费 |
| `pricing_note: "Audio enabled costs 2x credits."`    | `audio` 为 `true` 时价格翻倍                                                                                         |

示例：`viewmax-c1`、`5s`、`768P` → 10；`seedance-2-0` reference-to-video、`8s`、`720p`、5 秒源视频 → `ceil(28 × 13)` = 364；`kling-2-6`、`5s`、`audio: true` → 110。

## 错误

校验按以下顺序进行，遇到第一个错误即返回：请求格式、禁止用途措辞、模型、模式、提示词长度、输入、选项、余额。全部通过之前不会扣费。所有错误都使用[错误信封](https://viewmax.studio/zh/docs/api/errors)。

| HTTP | `error.type`           | `message` 示例                                                                                                            | 处理方式                                                                                                              |
| ---- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| 400  | `invalid_request`      | `unsupported video model: sora-3`                                                                                         | 使用 `GET /api/v1/models` 中的 `id`                                                                                   |
| 400  | `invalid_request`      | `video model temporarily unavailable: sora-2. The provider is not serving this model right now — pick a different model.` | 换用其他模型                                                                                                          |
| 400  | `invalid_request`      | `This capability is unavailable.`                                                                                         | 该模型或模式已停用（如 Motion Control），换用其他                                                                     |
| 400  | `invalid_request`      | `viewmax-c1 does not support mode video-to-video`                                                                         | 使用该模型 `modes` 中的键                                                                                             |
| 400  | `invalid_request`      | `minimax-h3 prompt must be 7000 characters or fewer, got 12459`                                                           | 缩短提示词                                                                                                            |
| 400  | `invalid_request`      | `viewmax-c1 frames-to-video requires image_urls (at least 2)`                                                             | 按[输入限制](#输入限制)补充输入                                                                                       |
| 400  | `invalid_request`      | `veo-3-1-fast reference-to-video supports at most 3 image_urls, got 4`                                                    | 减少 URL 数量                                                                                                         |
| 400  | `invalid_request`      | `veo-3-1 image-to-video does not accept video_urls; supported inputs: image_urls`                                         | 去掉 `video_urls` 或更换 `mode`                                                                                       |
| 400  | `invalid_request`      | `image_urls must contain valid http(s) URLs`                                                                              | 发送 `http://` 或 `https://` URL                                                                                      |
| 400  | `invalid_request`      | `seedance-2-0 reference-to-video requires options.source_video_duration_seconds when video_urls is provided`              | 发送源视频秒数                                                                                                        |
| 400  | `invalid_request`      | `runway text-to-video supports duration 5s at 1080p, got 10s`                                                             | 发送目录中列出的值                                                                                                    |
| 400  | `invalid_request`      | `viewmax-c1 text-to-video supports audio false, got true`                                                                 | 仅在 `audio_toggle` 为 `true` 时传 `audio: true`                                                                      |
| 400  | `invalid_request`      | `the generation request uses unsupported settings`，并带 `error.task_id`                                                  | 提供方拒绝了这些设置，任务已失败并退还积分。读取该任务的 `taskInfo.errorMessage`，调整后用新的 `Idempotency-Key` 重试 |
| 400  | `content_rejected`     | `input content was rejected by safety filters`                                                                            | 提示词含禁止用途措辞（深度伪造、换脸、冒充他人，否定句中出现也会拦截），或被提供方审核拒绝。修改内容，不要原样重试    |
| 402  | `insufficient_credits` | `insufficient credits`                                                                                                    | 未创建任务。补充积分前不要重试                                                                                        |
| 500  | `internal_error`       | `the generation service is temporarily unavailable`                                                                       | 带 `error.task_id` 时任务已失败并退还积分，可重试一次。若 hint 说明结果未知，请轮询该任务，不要重试                   |
| 503  | `internal_error`       | —                                                                                                                         | 内容安全检查暂不可用，稍后重试                                                                                        |

## 旧版 `/api/ai/*` 端点

旧版 `POST /api/ai/generate` 和 `POST /api/ai/query` 仍可供已有集成使用，并保持旧的请求形态与响应行为。新集成应使用这里的 v1 资源端点：`POST /api/v1/videos` 和 `GET /api/v1/tasks/{taskId}`。
