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

# 非同期タスク API

> 生成タスクを送信すると、1秒未満でタスク ID が返されます。画像の準備が完了したら、ポーリングするかコールバックを受け取れます。

非同期タスク API は、2 つのエンドポイントと 1 つのリクエストエンベロープで構成されます。タスクを送信すると、すぐに ID が返され、生成は WideRouter 側で実行されます。
モデルの処理中も、リクエスト側で接続を維持する必要はありません。

<Info>
  HTTP 接続を 20–50 秒間開いたままにする必要がある場合は、この API を使用してください。すでに動作する同期インテグレーションがある場合は、移行する前に
  [同期または非同期の選択](#choosing-sync-or-async)を参照してください。
</Info>

## エンドポイント

| メソッド   | パス                   | 目的                            |
| ------ | -------------------- | ----------------------------- |
| `POST` | `/v1/tasks/submit`   | タスクを作成します。タスク ID を直ちに返します。    |
| `GET`  | `/v1/task/{task_id}` | タスクのステータスを読み取り、完了後は出力も読み取ります。 |

作成時のパスは複数形で、**読み取り時は単数形**であることに注意してください。リスト、キャンセル、削除のエンドポイントはありません。

## タスクを作成する

リクエストボディは、常に次の3つのキーを持つエンベロープです。
`model`、`input`、およびオプションの`callback_url`です。

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.widerouter.com/v1/tasks/submit \
    -H "Authorization: Bearer $WIDEROUTER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gemini-3-pro-image",
      "input": {
        "prompt": "a small ceramic teapot on a light-grey studio backdrop",
        "aspect_ratio": "16:9",
        "image_size": "2K"
      }
    }'
  ```

  ```python Python theme={null}
  import os, requests

  resp = requests.post(
      "https://api.widerouter.com/v1/tasks/submit",
      headers={"Authorization": f"Bearer {os.environ['WIDEROUTER_API_KEY']}"},
      json={
          "model": "gemini-3-pro-image",
          "input": {
              "prompt": "a small ceramic teapot on a light-grey studio backdrop",
              "aspect_ratio": "16:9",
              "image_size": "2K",
          },
      },
      timeout=30,
  )
  task_id = resp.json()["id"]
  ```

  ```javascript Node theme={null}
  const resp = await fetch("https://api.widerouter.com/v1/tasks/submit", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.WIDEROUTER_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gemini-3-pro-image",
      input: {
        prompt: "a small ceramic teapot on a light-grey studio backdrop",
        aspect_ratio: "16:9",
        image_size: "2K",
      },
    }),
  });
  const { id } = await resp.json();
  ```
</CodeGroup>

レスポンスは3つのフィールドで構成され、1秒未満で返されます。

```json theme={null}
{
  "id": "task_dksUgWLYX4jIVueCACD8KwJzjR5JhRsI",
  "status": "queued",
  "created_at": 1788104112
}
```

### エンベロープのフィールド

| フィールド          | 型      | 必須  | 備考                                                   |
| -------------- | ------ | --- | ---------------------------------------------------- |
| `model`        | string | はい  | [サポートされているモデル](#supported-models)を参照してください。          |
| `input`        | object | はい  | JSONオブジェクトである必要があります。文字列または配列は拒否されます。                |
| `callback_url` | string | いいえ | `https` URLである必要があります。[コールバック](#callbacks)を参照してください。 |

エンベロープレベルの未知のキーは現在受け付けられ、無視されます。ただし、
この動作に依存せず、生成パラメータをそこに配置しないでください。生成パラメータは`input`に指定します。

### `input`オブジェクト

`input`には生成パラメータが含まれ、**受け付けるフィールドはモデルによって異なります**。その周囲のエンベロープは固定されていますが、内容は固定されていません。

`input`内のバリデーションは厳格です。モデルが認識しないキーはすべて
即座に拒否されるため、タイプミスを見逃さずに検出できます。

```json theme={null}
{ "error": { "code": "invalid_params", "message": "unknown field", "param": "input.negative_prompt" } }
```

<Card title="Nano Banana シリーズ" icon="layers" href="/ja/models/nano-banana/overview">
  フィールドの完全な一覧、解像度の段階、アスペクト比、および画像編集。
</Card>

## 結果をポーリングする

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.widerouter.com/v1/task/task_dksUgWLYX4jIVueCACD8KwJzjR5JhRsI \
    -H "Authorization: Bearer $WIDEROUTER_API_KEY"
  ```

  ```python Python theme={null}
  import os, time, requests

  def wait(task_id, timeout=600):
      headers = {"Authorization": f"Bearer {os.environ['WIDEROUTER_API_KEY']}"}
      deadline = time.time() + timeout
      while time.time() < deadline:
          task = requests.get(
              f"https://api.widerouter.com/v1/task/{task_id}",
              headers=headers, timeout=30,
          ).json()
          if task["status"] in ("completed", "failed"):
              return task
          time.sleep(3)
      raise TimeoutError(task_id)
  ```
</CodeGroup>

完了したタスクは次のようになります。

```json theme={null}
{
  "id": "task_dksUgWLYX4jIVueCACD8KwJzjR5JhRsI",
  "model": "gemini-3-pro-image",
  "status": "completed",
  "created_at": 1788104112,
  "started_at": 1788104113,
  "completed_at": 1788104131,
  "expires_at": 1788190531,
  "outputs": [
    "https://r2cdn.agisuitepro.com/o/2026/08/30/task_dksUgWLYX4jIVueCACD8KwJzjR5JhRsI_0.jpg"
  ],
  "counts": { "requested": 1, "succeeded": 1, "failed": 0 }
}
```

### タスクのフィールド

| フィールド          | 存在する場合          | 備考                                             |
| -------------- | --------------- | ---------------------------------------------- |
| `id`           | 常に              | タスク ID です。                                     |
| `model`        | 読み取り時は常に        | そのまま返されます。作成レスポンスには含まれません。                     |
| `status`       | 常に              | `queued`、`in_progress`、`completed`、`failed`です。 |
| `created_at`   | 常に              | Unix 秒、UTC です。                                 |
| `started_at`   | `in_progress`から | ワーカーがタスクを取得した時刻です。                             |
| `completed_at` | 終端状態            | `failed`を含みます。                                 |
| `expires_at`   | `completed`     | `created_at`に 24 時間を加えた値です。                    |
| `outputs`      | `completed`     | 画像 URL の配列です。リクエストした画像ごとに 1 つ含まれます。            |
| `counts`       | 終端状態            | `requested`、`succeeded`、`failed`です。            |
| `error`        | `failed`        | `code`と`message`を含むオブジェクトです。                   |

レスポンスはタスクの進行に応じて拡張されます。タスクの実行中は、`outputs`と`expires_at`は単に存在しません。固定された形状を前提にせず、フィールドを防御的に読み取り、まず`status`に基づいて分岐してください。

### ステータスの流れ

```
queued ──► in_progress ──► completed
                       └─► failed
```

両方の終端状態は最終状態であり、読み取りエンドポイントはべき等です。完了したタスクを繰り返し読み取ると、バイト単位で同一の JSON が返されます。

### 待機時間

送信処理は 1 秒未満で完了し、負荷がかかってもその状態が維持されます。同時実行数 12 で 30 件のタスクを処理した測定では、p50 は 0.88 秒、p95 は 0.92 秒でした。時間がかかるのは生成処理自体で、モデルと解像度に応じておよそ 12～50 秒です。そのうち 0～11 秒はキュー待ちに費やされます。モデルごとの数値は各モデルのページに記載されています。

<Warning>
  2～3 秒ごとにポーリングし、短い間隔でループしないでください。読み取りには単独でも往復に約 0.9 秒かかるため、それより速くポーリングしても何も得られず、レート制限を消費するだけです。
</Warning>

## 出力のダウンロード

`outputs`は、署名やクエリ文字列を含まないプレーンな`https`URLで、APIとは異なるホスト名のWideRouterの配信CDNから提供されます。これにより、次の2点が導かれます。

<Steps>
  <Step title="認証されていません">
    APIキーを送信してはいけません。また、URL自体を秘密情報として扱ってください。
    リンクを持っている人は誰でも、そのURLが有効な間は画像を取得できます。
  </Step>

  <Step title="24時間後に期限切れになります">
    `expires_at`は常に`created_at`に86400を加えた値です。保持する必要があるものはすべて
    自分のストレージにコピーしてください。出力URLを永続的な参照として保存してはいけません。
  </Step>
</Steps>

<Warning>
  **ダウンロード時には`User-Agent`ヘッダーを送信してください。** CDNの背後にはWAFがあり、
  `User-Agent`がないリクエストや、デフォルトの`Python-urllib/3.x`のリクエストに対して、
  空の`403`を返します。期限切れのリンクとまったく同じように見えますが、実際には異なります。
  動作確認済み: ブラウザ、`curl`、`requests`、`axios`、`okhttp`、Java、Go、
  Postman。動作しないもの: ヘッダーのない生の`urllib.request.urlopen(url)`。
</Warning>

```python theme={null}
import urllib.request

req = urllib.request.Request(url, headers={"User-Agent": "my-app/1.0"})
with urllib.request.urlopen(req, timeout=120) as r:
    data = r.read()
```

画像は、C2PAコンテンツ認証情報マニフェストを含むJPEGとして返されます。測定されたファイルサイズは、
`1K`で約0.4～0.7 MB、`2K`で2.4～3.0 MB、`4K`で7.5～8.2 MBです。
ファイル拡張子を推測するのではなく、レスポンスから`Content-Type`を読み取ってください。

## コールバック

作成時に `callback_url` を設定すると、WideRouter が完了したタスクをそこに POST するため、
ポーリングを完全に省略できます。

```json theme={null}
{
  "model": "gemini-3-pro-image",
  "input": { "prompt": "a paper crane" },
  "callback_url": "https://your-app.example/hooks/widerouter"
}
```

URL は `https` でなければなりません。それ以外のもの — `http`、ホスト名のみの値、文字列以外の値 —
は送信時に `invalid_callback_url` で拒否されるため、誤記があっても、配信されないまま気づけないのではなく、
すぐに失敗します。

WideRouter はタスクオブジェクトを `application/json` として POST します。本文を解析する前に
ルーティングに使用できるヘッダーも含まれます。

| ヘッダー             | 値                  |
| ---------------- | ------------------ |
| `X-Wide-Event`   | `task.completed`   |
| `X-Wide-Task-Id` | タスク ID             |
| `Content-Type`   | `application/json` |

本文は、その時点で `GET /v1/task/{task_id}` が返す内容とバイト単位で同一です —
フィールドも値も同じであるため、1つのハンドラーで両方の経路に対応できます。

テストでは配信は即時に行われました。3つのタスクのコールバックはすべて、タスクが
`completed` に到達してから1秒以内に届きました。エンドポイントが `5xx` を返した場合、
WideRouter は再試行します。確認された試行は、およそ0秒、10秒後、70秒後でした。

<Warning>
  **コールバックには署名がありません。** HMAC ヘッダーはなく、リクエストが WideRouter から送信されたことを
  証明するのは URL だけです。ペイロードは正式な情報源ではなくヒントとして扱ってください。`callback_url`
  には推測しにくい長いパスを使用し、重要な処理を行う前にハンドラーで `GET /v1/task/{task_id}` を
  再読み込みしてください。
</Warning>

<Info>
  コールバックはレイテンシーを最適化するものであり、配信を保証するものではありません。コールバックが届かない
  タスクに備えてポーリングのフォールバックを維持し、ハンドラーは冪等にしてください —
  再試行によって同じタスクが複数回届く可能性があるため、タスク `id` をキーにします。
</Info>

## タスクが失敗した場合

`failed`タスクは、readエンドポイントでは依然として`200`です。失敗しているのはHTTPステータスではなく、
ボディです。

```json theme={null}
{
  "id": "task_jodb26qdNoG5CuwzA23OukOgjeH5ktnh",
  "model": "gemini-3-pro-image",
  "status": "failed",
  "created_at": 1788104830,
  "started_at": 1788104831,
  "completed_at": 1788104831,
  "counts": { "requested": 1, "succeeded": 0, "failed": 1 },
  "error": { "code": "input_fetch_error", "message": "fetch input image failed: ..." }
}
```

`outputs`も`expires_at`もない点に注意してください。入力取得の失敗は、モデル処理の前に発生するため高速で、
1秒未満です。

## 送信時のエラー

バリデーションは何かがキューに追加される前に行われるため、ここでの`400`には費用がかかりません。

| HTTP | `code`                 | 意味                                                       |
| ---- | ---------------------- | -------------------------------------------------------- |
| 400  | `invalid_params`       | 不正なフィールドです。`param`がその名前を正確に示します（例：`input.aspect_ratio`）。 |
| 400  | `invalid_callback_url` | `callback_url`は`https` URLではありません。                       |
| 400  | `model_not_supported`  | 実在するモデルですが、非同期 API では利用できません。                            |
| 401  | —                      | `Authorization`ヘッダーがないか、無効です。                            |
| 404  | `task_not_found`       | そのタスク IDが存在しないか、お使いのキーに属していません。                          |
| 503  | `model_not_found`      | モデル名がプラットフォーム上に存在しません。                                   |

エラーは一度に1つのフィールドを指し、`param`は配列インデックス（`input.images[0]`）を含む完全なパスを使用するため、失敗箇所をリクエストに直接対応付けられます。

## ここで利用できるモデル

モデル ID は**完全一致**で照合されます。エイリアスはなく、`-preview`が付いた
名前は受け付けられません。非同期 API で提供されていない ID を送信すると、
キューに追加される前の送信時点で`model_not_supported`が返されます。

<Card title="Nano Banana シリーズ" icon="layers" href="/ja/models/nano-banana/overview">
  Google の画像モデル — 各提供先での利用可否、パラメータ、実測レイテンシ。
</Card>

## 同期と非同期の選択

どちらの方式も利用でき、いずれも非推奨ではありません。

|                   | 非同期タスク API    | 同期画像 API                            |
| ----------------- | ------------- | ----------------------------------- |
| クライアントが接続を保持するか   | いいえ、約 0.9 秒   | はい、12–50 秒                          |
| 結果の配信             | CDN URL、24 時間 | レスポンスボディ内の base64                   |
| 処理中にクライアントが切断した場合 | タスクは完了する      | 結果は失われ、リクエストの課金は発生する                |
| 1 回の呼び出しで複数の画像    | `n` 最大 4 枚    | 利用不可 — `n` は受け付けられて無視され、1 枚の画像が返される |
| コールバック            | はい            | いいえ                                 |

サーバーレス関数、リバースプロキシ、またはモバイルクライアントの背後で実行する処理では、50 秒のリクエストに確実に耐えられるものはないため、通常は非同期のほうが適しています。単にバイト列を受け取りたいスクリプトでは、同期呼び出しのほうがシンプルです。

## 次のステップ

<CardGroup cols={2}>
  <Card title="Nano Banana シリーズ" icon="layers" href="/ja/models/nano-banana/overview">
    パラメータマトリクス、解像度の段階、および2つのモデルの違い。
  </Card>

  <Card title="クイックスタート" icon="rocket" href="/ja/quickstart">
    エンドツーエンドの同じフローを約5分で実行できます。
  </Card>
</CardGroup>
