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

# Webhook

> 配信ペイロード、再試行スケジュール、安全なハンドラーの書き方。

タスクに `webhook.url` を指定すると、タスクが終了状態(`COMPLETED` または `FAILED`)に達したときに
結果をそこへPOSTします。

```json theme={null}
{
  "taskType": "PERPLEXITY",
  "payload": { "prompt": "best wireless earbuds 2026" },
  "webhook": { "url": "https://your-server.example.com/hook" }
}
```

## 配信ペイロード

`Content-Type: application/json` で次の本文をPOSTします。

<ResponseField name="task" type="object" required>
  送信時に受け取ったものと同じタスクメタデータです。終了 `status` を持ち、送信した `idempotencyKey` も返されます。
</ResponseField>

<ResponseField name="credits" type="object" required>
  エンジンごとのクレジットコストです。Perplexity は `2`、ChatGPT は `3` といった具合です(エンジンにより
  1–3クレジット)。タスクが失敗した場合 `creditsCharged` は `0` です。常にゼロを返す送信・ポーリングの
  レスポンスと違い、このフィールドはゼロ以外の値を持ちます。
</ResponseField>

<ResponseField name="response" type="object" required>
  エンジン固有の結果です。[エンジン](/ja/engines/overview)を参照してください。失敗したタスクでは、エンジンの
  結果の代わりに `{ "error": "<reason>" }` が入ります。
</ResponseField>

```json theme={null}
{
  "task": {
    "id": "8f2c1e40-...",
    "taskType": "PERPLEXITY",
    "status": "COMPLETED",
    "priority": 1,
    "createdAt": "2026-07-09T04:12:00.000Z",
    "idempotencyKey": "job-42:prompt-7:perplexity"
  },
  "credits": { "creditsToCharge": 3, "creditsCharged": 3 },
  "response": {
    "text": "The best wireless earbuds in 2026 are ...",
    "sources": [{ "position": 1, "url": "https://...", "label": "..." }]
  }
}
```

失敗したタスクも配信されます。

```json theme={null}
{
  "task": { "id": "8f2c1e40-...", "status": "FAILED", "...": "..." },
  "credits": { "creditsToCharge": 3, "creditsCharged": 0 },
  "response": { "error": "ENGINE_TIMEOUT: The engine did not answer before the task deadline." }
}
```

## 再試行

受信確認には任意の `2xx` を返してください。それ以外はタイムアウトを含めてすべて失敗とみなし、
指数バックオフで再試行します。

| 試行 | 送信タイミング |
| - | - |
| 1 | 即時 |
| 2 | 2分後 |
| 3 | 4分後 |
| 4 | 8分後 |
| 5 | 16分後 |

5回目の試行の後、配信は破棄されログに記録されます。参照できるデッドレターキューはありません。タスクAPIで
結果を取得するには、24時間の公開ポーリング期間内にポーリングしてください。この期間は元のレコードの保存期間を
定めるものではありません。

各試行のリクエストタイムアウトは**30秒**です。

<Warning>
  タスクから見ると配信は送りっぱなしです。完了したもののWebhookを配信できなかったタスクも、
  `GET /v1/async/task/{id}` では `COMPLETED` と表示されます。ステータスは通知ではなくエンジンの処理を表します。
</Warning>

## 安全なハンドラーを書く

<Steps>
  <Step title="すばやく受信確認する">
    ペイロードを永続的にキューへ入れたら、すぐに `200` を返してください。解析やデータベース書き込みは
    その後で行います。遅いハンドラーは30秒のタイムアウトを使い切り、不要な再試行を招きます。
  </Step>

  <Step title="idempotencyKeyで重複を除く">
    再試行があるため、ハンドラーが同じタスクを複数回受け取るのは正常です。`task.idempotencyKey`
    (または `task.id`)で照合し、書き込みを冪等にしてください。
  </Step>

  <Step title="有無ではなくstatusで分岐する">
    `task.status === "FAILED"` を明示的に確認してください。失敗したタスクもWebhookを配信します。
  </Step>
</Steps>

<Note>
  Webhookリクエストには署名も共有シークレットもありません。エンドポイントが公開されている場合は、
  ペイロードを信頼せず、推測されにくいURLパスを使うか、ネットワークレベルの制限の背後にハンドラーを置いてください。
</Note>
