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

# 影片生成

> 使用 AIHubMix 原生影片協定建立非同步任務、查詢狀態並下載影片。

<Note>
  [模型 Schema 介面](/zh-Hant/api/async-tasks#model-schema)
</Note>

## 快速開始

影片生成固定為非同步；以下使用 `wan2.6-t2v`，並以整數 `duration` 表示秒數。

<CodeGroup>
  ```bash 建立任務 theme={null}
  curl -X POST https://aihubmix.com/ai/v1/videos \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "wan2.6-t2v",
      "prompt": "Ocean waves crashing on rocky cliffs at sunset",
      "duration": 5,
      "size": "1280x720"
    }'
  ```

  ```json 建立回應 theme={null}
  {
    "id": "task_01K0ABCDEF",
    "object": "video",
    "model": "wan2.6-t2v",
    "status": "in_progress",
    "output": [],
    "error": null,
    "created_at": 1784707200,
    "completed_at": null,
    "expires_at": null
  }
  ```

  ```bash 查詢任務 theme={null}
  curl https://aihubmix.com/ai/v1/videos/{id} \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY"
  ```

  ```bash 下載結果 theme={null}
  curl https://aihubmix.com/ai/v1/videos/{id}/content \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
    --output result.mp4
  ```
</CodeGroup>

<h2 id="model-schema">
  如何探索非同步媒體模型並取得 Schema
</h2>

探索流程分為兩個步驟。先從公開模型目錄取得支援非同步介面的文生圖或文生影片模型，再使用模型的 `model_id` 取得對應端點的請求 Schema。

<h3 id="async-media-model-list">
  取得支援非同步介面的模型清單
</h3>

模型目錄與 Playground 使用相同的資料來源。`type=image_generation` 回傳文生圖模型，`type=video` 回傳文生影片模型。加入 `schema_checked=true` 後，清單只包含已發布並核對請求 Schema 的模型。

```bash theme={null}
# 文生圖模型
curl "https://aihubmix.com/api/v1/models?type=image_generation&schema_checked=true&sort_by=order"

# 文生影片模型
curl "https://aihubmix.com/api/v1/models?type=video&schema_checked=true&sort_by=order"
```

兩個請求使用同一個介面。`type` 篩選目前只接受一個值，因此需要分別請求兩種模型類型。

回應格式為 `{success, message, data}`。`data` 中與非同步媒體整合相關的欄位如下。

| 欄位                        | 說明                                          |
| ------------------------- | ------------------------------------------- |
| `data[].model_id`         | 用於生成請求和後續 Schema 查詢的模型 ID                   |
| `data[].model_name`       | 模型顯示名稱                                      |
| `data[].types`            | 逗號分隔的模型類型，可能同時包含 `image_generation` 和 `llm` |
| `data[].input_modalities` | 逗號分隔的輸入模態                                   |
| `data[].schema_checked`   | `true` 代表請求 Schema 已發布並完成核對                 |

```json theme={null}
{
  "success": true,
  "message": "",
  "data": [
    {
      "model_id": "qwen-image-2.0",
      "model_name": "Qwen Image 2.0",
      "types": "image_generation",
      "input_modalities": "text,image",
      "schema_checked": true
    }
  ]
}
```

<h3 id="single-model-schema">
  取得單一模型的請求 Schema
</h3>

不同模型支援的欄位、列舉和數值範圍可能不同。提交圖片或影片請求前，可以透過同一個公開介面取得指定模型目前可用的端點和請求 JSON Schema。

```bash theme={null}
# 文生圖模型
curl "https://aihubmix.com/call/schema/models/qwen-image-2.0/endpoints"

# 文生影片模型
curl "https://aihubmix.com/call/schema/models/wan2.6-t2v/endpoints"
```

回應中的 `modality` 為 `image` 或 `video`。`endpoints` 陣列中的每一項描述一個可用的呼叫協定。

| 欄位                           | 說明                                     |
| ---------------------------- | -------------------------------------- |
| `default_endpoint`           | 目前模型的預設端點識別碼                           |
| `endpoints[].endpoint`       | 端點識別碼                                  |
| `endpoints[].method`         | 請求方法，例如 `POST`                         |
| `endpoints[].path`           | 實際提交路徑                                 |
| `endpoints[].content_types`  | 端點接受的內容類型                              |
| `endpoints[].lifecycle`      | 同步或非同步模式、輪詢路徑和狀態值                      |
| `endpoints[].request.schema` | 該模型在對應端點下的完整請求 JSON Schema，包括必填欄位和取值限制 |

同一個模型可能同時回傳 `/ai/v1` 與 OpenAI 相容 `/v1` 端點。OpenAI 相容介面可能暫不支援最新模型，請優先使用 `/ai/v1` 端點。非同步任務介面應依 `path` 選擇 `/ai/v1/images/generations` 或 `/ai/v1/videos`，再讀取該項目的 `request.schema`。不要依賴 `endpoints` 陣列位置。

下面的命令可以直接擷取兩個非同步任務端點的請求 Schema。

```bash theme={null}
# 文生圖
curl -s "https://aihubmix.com/call/schema/models/qwen-image-2.0/endpoints" \
  | jq '.endpoints[] | select(.path == "/ai/v1/images/generations") | .request.schema'

# 文生影片
curl -s "https://aihubmix.com/call/schema/models/wan2.6-t2v/endpoints" \
  | jq '.endpoints[] | select(.path == "/ai/v1/videos") | .request.schema'
```

模型不存在或尚未提供可探索端點時，介面回傳 `404 model_not_found`。端點資料暫時無法使用時回傳 `500 endpoints_unavailable`。

***

<h2 id="create-async-video">
  如何建立影片任務
</h2>

影片請求一律非同步，不支援透過 `Prefer: wait` 改為同步等待。標準協定使用整數 `duration` 表示秒數：

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/videos \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan2.6-t2v",
    "prompt": "Ocean waves crashing on rocky cliffs at sunset",
    "duration": 5,
    "size": "1280x720"
  }'
```

<h3 id="video-parameters">
  影片標準欄位
</h3>

| 欄位                      | 類型           | 必填 | 說明                                                   |
| ----------------------- | ------------ | -- | ---------------------------------------------------- |
| `model`                 | string       | 是  | 模型名稱                                                 |
| `prompt`                | string       | 是  | 影片描述，不可為空                                            |
| `duration`              | integer/null | 否  | 影片時長，單位為秒；具體範圍由模型決定                                  |
| `aspect_ratio`          | string/null  | 否  | 長寬比，協定預設值為 `16:9`                                    |
| `resolution`            | string/null  | 否  | `480p`、`720p`、`1080p`、`1K`、`2K` 或 `4K`               |
| `size`                  | string/null  | 否  | `{width}x{height}`；可取代 `resolution` 與 `aspect_ratio` |
| `seed`                  | integer/null | 否  | 隨機種子                                                 |
| `input_references`      | array/null   | 否  | 圖片、影片或音訊參考素材                                         |
| `frame_images`          | array/null   | 否  | 首幀或尾幀圖片                                              |
| `generate_audio`        | boolean/null | 否  | 是否生成音軌                                               |
| `webhook_url`           | string       | 否  | HTTPS 回呼位址，最長 512 個字元                                |
| `webhook_events_filter` | string\[]    | 否  | `completed`、`failed`、`cancelled` 的非空子集               |
| `extra`                 | object/null  | 否  | 特定模型的擴充參數                                            |

`input_references` 項目的結構：

```json theme={null}
{
  "type": "image_url",
  "url": "https://example.com/reference.png"
}
```

`type` 可以是 `image_url`、`video_url` 或 `audio_url`。

`frame_images` 項目的結構：

```json theme={null}
{
  "frame_type": "first_frame",
  "image_url": {
    "url": "https://example.com/first-frame.png"
  }
}
```

`frame_type` 可以是 `first_frame` 或 `last_frame`。

***

<h2 id="task-object">
  媒體任務物件
</h2>

圖片和影片專用介面回傳以下結構：

```json theme={null}
{
  "id": "task_01K0ABCDEF",
  "object": "video",
  "model": "wan2.6-t2v",
  "status": "completed",
  "output": [
    {
      "index": 0,
      "type": "file",
      "b64_json": null,
      "content_url": "https://aihubmix.com/ai/v1/videos/task_01K0ABCDEF/content"
    }
  ],
  "error": null,
  "created_at": 1784707200,
  "completed_at": 1784707320,
  "expires_at": null
}
```

| 欄位             | 類型           | 說明                                            |
| -------------- | ------------ | --------------------------------------------- |
| `id`           | string       | 平台任務 ID                                       |
| `object`       | string       | `image` 或 `video`                             |
| `model`        | string       | 模型名稱                                          |
| `status`       | string       | 目前任務狀態                                        |
| `output`       | array        | 已生成的結果；尚無結果時為空陣列                              |
| `error`        | object/null  | 失敗資訊，可包含 `code`、`message` 和 `upstream_detail` |
| `created_at`   | integer      | 建立時間，Unix 秒                                   |
| `completed_at` | integer/null | 最終狀態時間，Unix 秒                                 |
| `expires_at`   | null         | 媒體專用介面目前回傳 `null`                             |

媒體 `output` 項目：

| 欄位            | 類型          | 說明             |
| ------------- | ----------- | -------------- |
| `index`       | integer     | 結果順序，從 `0` 開始  |
| `type`        | string      | 目前為 `file`     |
| `content_url` | string/null | 結果下載位址         |
| `b64_json`    | string/null | Base64 編碼的圖片結果 |

<h3 id="task-status">
  狀態說明
</h3>

| 狀態            | 是否結束 | 說明                |
| ------------- | ---- | ----------------- |
| `pending`     | 否    | 平台已接收任務，等待執行      |
| `in_progress` | 否    | 任務正在執行            |
| `completed`   | 是    | 任務完成，可讀取 `output` |
| `failed`      | 是    | 任務失敗，原因請見 `error` |
| `cancelled`   | 是    | 任務已取消             |

用戶端可以每 15 秒查詢一次，直到狀態變為 `completed`、`failed` 或 `cancelled`。15 秒是用戶端輪詢建議，不是伺服器協定限制。

***

<h2 id="query-tasks">
  如何查詢媒體任務
</h2>

<h3 id="query-task-detail">
  查詢媒體詳情
</h3>

```bash theme={null}
# 圖片
curl https://aihubmix.com/ai/v1/images/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"

# 影片
curl https://aihubmix.com/ai/v1/videos/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

媒體詳情介面可回傳更新後的任務狀態，因此媒體輪詢應使用對應的圖片或影片詳情介面。

<h3 id="query-task-list">
  查詢媒體清單
</h3>

建立回應遺失時，可以透過對應媒體清單找回任務 ID：

```bash theme={null}
curl "https://aihubmix.com/ai/v1/videos?limit=20&order=desc" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

| 參數      | 類型      | 預設值    | 說明                          |
| ------- | ------- | ------ | --------------------------- |
| `after` | string  | -      | 分頁游標，使用上一頁的 `next_after`    |
| `limit` | integer | `20`   | 每頁數量，最大 `100`               |
| `order` | string  | `desc` | 傳入 `asc` 時升冪，其他值按 `desc` 處理 |

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "task_01K0ABCDEF",
      "object": "video",
      "model": "wan2.6-t2v",
      "status": "in_progress",
      "output": [],
      "error": null,
      "created_at": 1784707200,
      "completed_at": null,
      "expires_at": null
    }
  ],
  "has_more": true,
  "next_after": "task_01K0ABCDEF"
}
```

媒體清單回傳查詢時的任務快照，不會主動更新任務狀態。

***

<h2 id="unified-tasks">
  如何使用統一任務介面
</h2>

統一任務介面支援以下篩選條件：

```bash theme={null}
curl "https://aihubmix.com/ai/v1/tasks?object=video&status=in_progress&limit=20&order=desc" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

| 參數       | 類型      | 預設值    | 說明                                                         |
| -------- | ------- | ------ | ---------------------------------------------------------- |
| `object` | string  | -      | `llm`、`image` 或 `video`                                    |
| `status` | string  | -      | `pending`、`in_progress`、`completed`、`failed` 或 `cancelled` |
| `model`  | string  | -      | 按模型名稱精確篩選                                                  |
| `after`  | string  | -      | 分頁游標                                                       |
| `limit`  | integer | `20`   | 範圍 `1` 到 `100`                                             |
| `order`  | string  | `desc` | `asc` 或 `desc`                                             |

統一任務詳情：

```bash theme={null}
curl https://aihubmix.com/ai/v1/tasks/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

媒體任務的統一 `output` 項目：

```json theme={null}
{
  "index": 0,
  "result_id": "result_01K0XYZ",
  "type": "file",
  "content_type": "video/mp4",
  "content_url": "https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF/content"
}
```

單一產物直接請求 `/ai/v1/tasks/{id}/content`。多產物任務需要請求 `/ai/v1/tasks/{id}/content/{result_id}`；未指定結果 ID 時回傳 `400 result_id_required`。

<Note>
  統一任務清單、詳情和內容介面按建立任務時的 Bearer Token 隔離。同一帳戶下的其他
  API Key 無法讀取該任務。
</Note>

***

<h2 id="get-task-results">
  如何下載媒體結果
</h2>

<h3 id="single-artifact">
  下載影片
</h3>

```bash theme={null}
curl https://aihubmix.com/ai/v1/videos/{task_id}/content \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  --output result.mp4
```

<Warning>
  結果可能過期，並且可能存在下載次數限制。過期回傳 `410
      artifact_expired`，超過下載次數限制回傳 `429 too_many_downloads`。
</Warning>

***

<h2 id="webhooks">
  如何使用 Webhook
</h2>

非同步圖片和影片支援任務層級 Webhook：

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/videos \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan2.6-t2v",
    "prompt": "A tranquil garden at sunrise",
    "duration": 5,
    "size": "1280x720",
    "webhook_url": "https://example.com/webhooks/aihubmix",
    "webhook_events_filter": ["completed", "failed"]
  }'
```

`webhook_url` 最長 512 個字元，並且不能指向本機、私人網路或其他受限位址。省略 `webhook_events_filter` 時，平台推送 `completed`、`failed` 和 `cancelled`；明確傳入時，陣列不可為空、不可重複，並且必須與 `webhook_url` 一起使用。

未在請求中傳入 `webhook_url` 時，非同步圖片和影片會嘗試使用帳戶中設定的預設回呼位址。無效的帳戶預設位址會被忽略，不會阻止任務建立。

<h3 id="webhook-payload">
  回呼請求
</h3>

```json theme={null}
{
  "event_id": "evt_01K0ABCDEF",
  "event_type": "completed",
  "created_at": "2026-08-12T12:00:00Z",
  "data": {
    "task_id": "task_01K0ABCDEF",
    "status": "completed",
    "model": "wan2.6-t2v",
    "results": [
      {
        "url": "https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF/content"
      }
    ]
  }
}
```

| 欄位                   | 說明                                 |
| -------------------- | ---------------------------------- |
| `event_id`           | 回呼事件 ID，用於去重                       |
| `event_type`         | `completed`、`failed` 或 `cancelled` |
| `created_at`         | RFC 3339 格式的事件時間                   |
| `data.task_id`       | 平台任務 ID                            |
| `data.status`        | 目前最終狀態                             |
| `data.model`         | 模型名稱                               |
| `data.results[].url` | 完成時可能回傳的結果下載位址                     |
| `data.error`         | 失敗時可能回傳的錯誤資訊                       |

`results` 僅在結果已存檔時出現，下載仍需要 Bearer Token。

<h3 id="webhook-retry">
  重試與去重
</h3>

平台採用至少一次投遞，同一個事件可能重複送達：

* HTTP `2xx` 表示接收成功。
* HTTP `5xx`、網路錯誤或逾時會觸發重試。
* HTTP `3xx` 和 `4xx` 不會重試。
* 最多投遞 6 次，重試間隔依序為 1、4、16、64、256 秒。

接收端應儲存 `event_id`，重複收到相同事件時直接回傳 `2xx`。

<Warning>
  任務層級 Webhook 本身不含獨立簽章金鑰。需要簽章驗證時，請設定帳戶層級 Webhook
  訂閱，並保留任務詳情查詢作為結果確認方式。
</Warning>

***

<h2 id="error-codes">
  錯誤回應與錯誤碼
</h2>

```json theme={null}
{
  "error": {
    "message": "Task not found.",
    "type": "invalid_request_error",
    "code": "task_not_found",
    "tid": "req_01K0ABCDEF"
  }
}
```

| HTTP 狀態碼 | 錯誤碼                             | 說明                            |
| -------- | ------------------------------- | ----------------------------- |
| 400      | `invalid_request`               | 參數類型或值不正確                     |
| 400      | `result_id_required`            | 統一任務有多個結果，但下載時未指定 `result_id` |
| 400      | `webhook_invalid`               | Webhook URL 不合法，或篩選器缺少 URL    |
| 400      | `webhook_events_filter_invalid` | Webhook 事件清單不合法               |
| 401      | `authentication_failed`         | API Key 缺少或無效                 |
| 403      | `async_not_enabled`             | 帳戶未開啟非同步任務功能                  |
| 404      | `task_not_found`                | 任務或分頁游標不存在                    |
| 404      | `result_not_found`              | 結果不存在或目前無法下載                  |
| 410      | `artifact_expired`              | 結果已過期                         |
| 413      | `request_too_large`             | 請求本文超過 32 MiB                 |
| 429      | `too_many_downloads`            | 超過結果下載次數限制                    |
| 503      | `async_unavailable`             | 非同步圖片服務暫時無法使用                 |

`error.tid` 是請求追蹤 ID，聯絡技術支援排查時請一併提供。

***

## 完整範例

以下範例會建立任務、輪詢並下載 MP4。

<CodeGroup>
  ```python Python theme={null}
  import os
  import time

  import requests

  base_url = "https://aihubmix.com"
  headers = {
      "Authorization": f"Bearer {os.environ['AIHUBMIX_API_KEY']}",
      "Content-Type": "application/json",
  }

  response = requests.post(
      f"{base_url}/ai/v1/videos",
      headers=headers,
      json={
          "model": "wan2.6-t2v",
          "prompt": "A cat playing jazz on a piano",
          "duration": 5,
          "size": "1280x720",
      },
      timeout=60,
  )
  response.raise_for_status()
  task = response.json()

  while task["status"] not in {"completed", "failed", "cancelled"}:
      time.sleep(15)
      response = requests.get(
          f"{base_url}/ai/v1/videos/{task['id']}",
          headers=headers,
          timeout=30,
      )
      response.raise_for_status()
      task = response.json()

  if task["status"] == "completed":
      result = requests.get(
          f"{base_url}/ai/v1/videos/{task['id']}/content",
          headers=headers,
          timeout=120,
      )
      result.raise_for_status()
      with open("result.mp4", "wb") as file:
          file.write(result.content)
  else:
      raise RuntimeError(task.get("error") or task["status"])
  ```

  ```typescript TypeScript theme={null}
  import { writeFile } from "node:fs/promises";

  const baseUrl = "https://aihubmix.com";
  const headers = {
    Authorization: `Bearer ${process.env.AIHUBMIX_API_KEY}`,
    "Content-Type": "application/json",
  };

  const created = await fetch(`${baseUrl}/ai/v1/videos`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      model: "wan2.6-t2v",
      prompt: "A cat playing jazz on a piano",
      duration: 5,
      size: "1280x720",
    }),
  });
  if (!created.ok) throw new Error(await created.text());
  let task = await created.json();

  const finished = new Set(["completed", "failed", "cancelled"]);
  while (!finished.has(task.status)) {
    await new Promise((resolve) => setTimeout(resolve, 15_000));
    const polled = await fetch(`${baseUrl}/ai/v1/videos/${task.id}`, { headers });
    if (!polled.ok) throw new Error(await polled.text());
    task = await polled.json();
  }

  if (task.status === "completed") {
    const result = await fetch(`${baseUrl}/ai/v1/videos/${task.id}/content`, {
      headers,
    });
    if (!result.ok) throw new Error(await result.text());
    await writeFile("result.mp4", Buffer.from(await result.arrayBuffer()));
  } else {
    throw new Error(JSON.stringify(task.error ?? task.status));
  }
  ```
</CodeGroup>
