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

# Webhooks

> リアルタイムのイベント通知を受信して処理する

## 概要

Webhook は、イベントをリアルタイムでサーバーにプッシュします。ポーリングは不要です。

```
Waffo Pancake でイベント発生 --> あなたのエンドポイントに HTTP POST --> イベントを処理
```

***

## セットアップ

<Steps>
  <Step title="HTTPS エンドポイントの作成">
    POST リクエストを受け付け、200 OK を返す、公開アクセス可能なエンドポイントを構築します。
  </Step>

  <Step title="ダッシュボードで登録">
    ダッシュボード > API と開発 > Webhooks に移動し、エンドポイント URL を追加します。
  </Step>

  <Step title="イベントの選択">
    受信するイベントを選択します。
  </Step>

  <Step title="保存">
    Webhook の設定を保存します。
  </Step>
</Steps>

***

## イベントタイプ

イベントは、決済、サブスクリプション、返金のライフサイクル通知をカバーしています。ダッシュボードで Webhook を設定する際に、受信するイベントカテゴリを選択できます。

<Note>
  正確なイベント名と利用可能なカテゴリは、Webhook エンドポイントの設定時にダッシュボードに表示されます。最新のリストについてはダッシュボードをご参照ください。
</Note>

***

## ペイロード形式

各 Webhook 配信は、イベントタイプと関連データを含む JSON ボディの HTTP POST です：

```json theme={"system"}
{
  "event": "<event_type>",
  "data": {
    // イベント固有のフィールド
  }
}
```

<Note>
  全ての ID は UUID v4 形式です。金額は表示形式の文字列です（例："29.00" = \$29.00）。タイムスタンプは ISO 8601 UTC です。
</Note>

***

## Webhook の処理

`200 OK` を速やかに返してください。ハンドラーで重い処理が必要な場合は、非同期で処理してください。

<CodeGroup>
  ```javascript Node.js (Express) theme={"system"}
  app.post('/webhooks/waffo', (req, res) => {
    // すぐにレスポンスを返す
    res.status(200).send('OK');

    // 非同期で処理
    const { event, data } = req.body;

    switch (event) {
      case 'order.completed':
        handleOrderCompleted(data);
        break;
      case 'subscription.activated':
        handleSubscriptionActivated(data);
        break;
      case 'subscription.canceled':
        handleSubscriptionCanceled(data);
        break;
    }
  });
  ```

  ```python Python (Flask) theme={"system"}
  from flask import Flask, request, jsonify

  app = Flask(__name__)

  @app.route('/webhooks/waffo', methods=['POST'])
  def handle_webhook():
      payload = request.get_json()
      event = payload.get('event')
      data = payload.get('data')

      if event == 'order.completed':
          handle_order_completed(data)
      elif event == 'subscription.activated':
          handle_subscription_activated(data)

      return jsonify({'received': True}), 200
  ```
</CodeGroup>

***

## 冪等性

イベントは複数回配信される可能性があります。重複排除にはイベントデータを使用してください：

```javascript theme={"system"}
const processedEvents = new Set();

app.post('/webhooks/waffo', (req, res) => {
  const { event, data } = req.body;
  const eventKey = `${event}:${data.id}`;

  if (processedEvents.has(eventKey)) {
    return res.status(200).send('Already processed');
  }

  processedEvents.add(eventKey);
  res.status(200).send('OK');
  processWebhook(event, data);
});
```

<Tip>
  本番環境では、サーバー再起動後も永続化されるよう、処理済みイベント ID をインメモリではなくデータベースに保存してください。
</Tip>

***

## リトライポリシー

配信に失敗した場合、自動的にリトライされます。受信を確認するため、エンドポイントが速やかに `200` ステータスコードを返すようにしてください。

***

## テスト

[テストモード](/ja/features/test-mode)を使用して Webhook をテストできます：

1. ダッシュボードでテストモードに切り替える
2. 開発者 > Webhooks に移動する
3. イベントをトリガーするアクションを実行する
4. エンドポイントに届くイベントを確認する

<Note>
  Webhook はテストモードとライブモードの両方で発火します。エンドポイントで環境を区別できるようにしてください。
</Note>

***

## ベストプラクティス

1. **HTTPS を使用する** -- 本番の Webhook エンドポイントには必須です
2. **速やかにレスポンスする** -- 30 秒以内に 200 を返してください
3. **重複を処理する** -- ID を使って重複排除してください
4. **非同期で処理する** -- 重い処理でレスポンスをブロックしないでください
5. **全てログに記録する** -- デバッグのために受信した Webhook を記録してください
