# 创建生成任务

`createGeneration`

`POST /v1/generations`

下面的接口说明为英文原文。

Each accepted POST durably records a separate generation. While pending_funding the reserved amount is zero. Funding success queues the job; check its status for a funding rejection. Submitting the same request twice can incur two charges. After a lost response, check the generation list before deciding to create another task.

## 鉴权

在请求头带上项目 Key，例如 `Authorization: Bearer $VIZO_API_KEY`。Key 只放在服务端。

## 请求体

- `input` (object, 必填) 生成参数。具体字段取决于模型和操作，见各模型页。
  - `aspect_ratio` (string, 可选)
  - `asset_id` (string, 可选) 最多 128 个字符
  - `duration_seconds` (integer, 可选) 最小 -1
  - `generate_audio` (boolean, 可选)
  - `native` (any, 可选)
  - `prompt` (string, 可选) 至少 1 个字符 最多 4000 个字符
  - `resolution` (string, 可选)
  - `source_generation_id` (string, 可选) 最多 128 个字符
  - `video` (object, 可选)
    - `bitrate_mode` (string, 可选)
    - `content` (object[], 可选, 可为 null)
      - `asset_id` (string, 可选)
      - `draft_generation_id` (string, 可选)
      - `role` (string, 可选)
      - `text` (string, 可选)
      - `type` (string, 必填)
      - `url` (string, 可选)
    - `draft` (boolean, 可选)
    - `execution_expires_after` (integer, 可选)
    - `moderation_options` (object, 可选)
      - `ips` (string[], 必填, 可为 null)
    - `omni_reference_task_type` (string, 可选)
    - `output_format` (string, 可选)
    - `return_last_frame` (boolean, 可选)
    - `safety_identifier` (string, 可选)
    - `seed` (integer, 可选)
    - `tools` (object[], 可选, 可为 null)
      - `type` (string, 必填)
    - `watermark` (boolean, 可选)
- `metadata` (map<string, string>, 可选) 你自己的字符串键值，原样返回。建议写入 client_reference，回包丢失时用它找回任务。
- `model` (string, 必填) 模型 ID，来自 listModels 或模型页。 至少 1 个字符
- `operation` (string, 必填) 生成类型。只接受该模型已发布的操作。 可选值: `text-to-video`, `image-to-video`, `reference-to-video`, `video-edit`, `video-extend`, `video-draft`, `draft-to-video`, `generate-image`, `generate-audio`, `clone-voice`, `generate-video`, `process-video`
- `quote_id` (string, 可选) 至少 1 个字符
- `routing` (object, 可选) 指定规格。不传时由平台选择该模型已发布的规格。
  - `mode` (string, 必填) 可选值: `pinned`
  - `route` (string, 必填) 至少 1 个字符
- `webhook_endpoint_id` (string, 可选) 任务状态变化时通知的 Webhook 端点，在控制台创建。

```json
{
  "model": "MODEL_FROM_PROJECT",
  "operation": "text-to-video",
  "input": {
    "prompt": "A paper boat drifting on a pond",
    "duration_seconds": 5
  }
}
```

## 响应

### 202 Accepted

- `allowed_actions` (string[], 必填, 可为 null) 当前可以执行的操作，例如 cancel。以这个列表为准，不要根据状态自行推断。
- `billing_status` (string, 必填) Credits 是冻结、已扣费还是已释放。
- `closed_at` (date-time, 必填, 可为 null) 任务关闭时间。不为空即可停止轮询。
- `customer_resolution_deadline` (date-time, 必填) 受理后 24 小时。到期仍未结算的冻结额度全部释放。
- `delivery_status` (string, 必填) 结果是否已保存、可下载。ready 表示可以下载。
- `error` (object, 必填, 可为 null) 任务未产出结果就关闭时才有值，读取 error.code。
  - `code` (string, 必填) 任务未产出结果就关闭的原因，例如 insufficient_balance、budget_exceeded 或 spending_blocked。
- `execution_status` (string, 必填) 模型生成进度。
- `id` (string, 必填) 资源 ID，收到后立即保存。
- `late_result_available` (boolean, 必填) 关闭后才到的结果，免费提供。
- `metadata` (map<string, string>, 可选) 你自己的字符串键值，原样返回。建议写入 client_reference，回包丢失时用它找回任务。
- `price` (object, 必填) 这个任务的 Credits：quoted 是受理时的价格，reserved 是冻结额度，charged 是实际扣费。结算前 charged 为 0.000。
  - `charged` (string, 必填)
  - `price_version` (string, 必填)
  - `quoted` (string, 必填)
  - `reserved` (string, 必填)
  - `unit` (string, 必填) 可选值: `credit`
- `result` (object, 必填, 可为 null) 交付后的素材。
  - `asset_id` (string, 可选)
  - `last_frame_asset_id` (string, 可选)
  - `metadata` (object, 可选)
    - `duration` (integer, 可选)
    - `frames` (integer, 可选)
    - `framespersecond` (integer, 可选)
    - `generate_audio` (boolean, 可选)
    - `ratio` (string, 可选)
    - `resolution` (string, 可选)
    - `seed` (integer, 可选)
  - `outputs` (object[], 可选, 可为 null)
    - `asset_id` (string, 必填)
    - `content_type` (string, 必填)
    - `index` (integer, 必填)
  - `voice_id` (string, 可选)
- `status` (string, 必填) 任务的总体状态。
- `version` (integer, 必填)

```json
{
  "allowed_actions": [
    "cancel"
  ],
  "billing_status": "held",
  "closed_at": null,
  "customer_resolution_deadline": "2026-11-03T08:00:12Z",
  "delivery_status": "pending",
  "error": null,
  "execution_status": "queued",
  "id": "gen_01JD8Z5QW3XR",
  "late_result_available": false,
  "metadata": {
    "client_reference": "order-1042"
  },
  "price": {
    "charged": "0.000",
    "price_version": "p3",
    "quoted": "1400.000",
    "reserved": "1400.000",
    "unit": "credit"
  },
  "result": null,
  "status": "queued",
  "version": 1
}
```

### 401 Unauthorized

```json
{
  "error": {
    "code": "invalid_credentials",
    "message": "API key is missing, malformed, expired or revoked.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 402 Payment Required

```json
{
  "error": {
    "code": "insufficient_balance",
    "message": "Available credits cannot cover the hold.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 403 Forbidden

```json
{
  "error": {
    "code": "scope_denied",
    "message": "The key does not allow this operation for this project.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 404 Not Found

```json
{
  "error": {
    "code": "resource_not_found",
    "message": "The resource is not available to this project.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 409 Conflict

```json
{
  "error": {
    "code": "conflict",
    "message": "The request conflicts with the current state of the resource.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 422 Unprocessable Entity

```json
{
  "error": {
    "code": "invalid_input",
    "message": "Input does not match the published schema.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 429 Too Many Requests

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Check Retry-After.",
    "retryable": true,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 500 Internal Server Error

```json
{
  "error": {
    "code": "request_failed",
    "message": "The request failed. Check recent generations before submitting again.",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

### 503 Service Unavailable

```json
{
  "error": {
    "code": "temporarily_unavailable",
    "message": "Service is temporarily unavailable.",
    "retryable": true,
    "request_id": "9f2c41d07ab3e5c8"
  }
}
```

## 错误

所有错误使用同一种响应体。联系支持时请附上 request_id。

### 错误响应体

- `error` (object, 必填) 错误详情。
  - `code` (string, 必填) 稳定的错误码，用它判断分支。
  - `message` (string, 必填) 可读的说明，不要解析它。
  - `request_id` (string, 必填) 联系支持时请附上。
  - `retryable` (boolean, 必填) 仅 429 和 503 为 true。即便如此，重发创建请求前也要先查看近期任务。
  - `task_id` (string, 可选) 错误所属的任务（如果有）。

| 状态码 | 含义与处理 |
| --- | --- |
| 401 | Key 缺失、格式错误、已过期或已撤销。在服务端更正 Key 后继续。 |
| 402 | 可用 Credits 不足以支付这次请求。充值并等待到账后，再查询余额。 |
| 403 | Key 权限、邮箱验证、预算上限或账户限制阻止了操作。检查 Key 类型、权限和项目预算。 |
| 404 | 模型或资源不存在，或不在当前项目范围内。确认项目、ID 和模型是否已开通。 |
| 409 | 请求与当前状态冲突。重新读取资源，再决定是否重新发送。 |
| 422 | 字段或取值无效。对照字段表和模型页修改请求。 |
| 429 | 请求过于频繁，没有创建任务。等到 Retry-After 指定的时间后再发送。 |
| 500 | 服务端出错，任务可能已经受理。不要直接重发，先查看近期任务。 |
| 503 | 服务暂时不可用。创建请求要先查看近期任务，确认没有受理，再重新提交。 |
| 超时或断连 | 没有响应或连接中断，任务可能已经受理。有任务 ID 就查询原任务；没有就按 client_reference 在任务列表中找回。 |

### cURL

```bash
curl -X POST "https://api.vizoapi.com/v1/generations" \
  -H "Authorization: Bearer $VIZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_FROM_PROJECT",
    "operation": "text-to-video",
    "input": {
      "prompt": "A paper boat drifting on a pond",
      "duration_seconds": 5
    }
  }'
```

### Python

```python
import os, requests

res = requests.post(
    "https://api.vizoapi.com/v1/generations",
    headers={"Authorization": f"Bearer {os.environ['VIZO_API_KEY']}"},
    json={
      "model": "MODEL_FROM_PROJECT",
      "operation": "text-to-video",
      "input": {
        "prompt": "A paper boat drifting on a pond",
        "duration_seconds": 5
      }
    },
    timeout=60,
)
print(res.status_code, res.json())
```

### Node.js

```javascript
const res = await fetch("https://api.vizoapi.com/v1/generations", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VIZO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "MODEL_FROM_PROJECT",
    "operation": "text-to-video",
    "input": {
      "prompt": "A paper boat drifting on a pond",
      "duration_seconds": 5
    }
  }),
});
console.log(res.status, await res.json());
```
