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

# Webhook - 処理のベストプラクティス

> Webhook 処理のベストプラクティス: 冪等性、高速応答、セキュリティなど。

## SDK 内蔵の WebhookHandler を使用する

SDK の `webhook().handleWebhook()` メソッドの利用を強く推奨します。次の処理を自動的に行います。

* 署名検証
* JSON パースとイベントルーティング
* 応答ボディの構築と署名

```typescript theme={null}
const handler = waffo.webhook()
  .onPayment((n) => handlePayment(n))
  .onRefund((n) => handleRefund(n))
  .onSubscriptionStatus((n) => handleSubscription(n))
  .onSubscriptionChange((n) => handleChange(n));

app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const result = await handler.handleWebhook(req.body.toString(), req.headers['x-signature'] as string);
  res.setHeader('X-SIGNATURE', result.responseSignature);
  res.status(200).send(result.responseBody);
});
```

## 冪等な処理

Waffo は同じイベントを複数回配信する場合があります。処理ロジックが冪等であることを確認してください。

```typescript theme={null}
waffo.webhook().onPayment(async (notification) => {
  const orderId = notification.acquiringOrderId;

  const order = await db.order.findByAcquiringOrderId(orderId);
  if (order.status === 'PAY_SUCCESS') {
    return;
  }

  await updateOrderStatus(orderId, notification.orderStatus);
});
```

## 配信順序ではなく最終状態で処理する

Webhook は非同期で配信されるため、関連する複数のコールバックを加盟店のエンドポイントが受信する順序は保証されません。サブスクリプションの初回期間では、`SUBSCRIPTION_STATUS_NOTIFICATION` と `SUBSCRIPTION_PERIOD_CHANGED_NOTIFICATION` の両方が送信される場合があります。この 2 つのコールバックの到着順序に依存しないでください。

* コールバックの到着順序だけで最終的なビジネス状態を更新しないでください
* `subscriptionId`、イベント ID、または加盟店側の注文 ID で冪等に重複排除してください
* `SUBSCRIPTION_STATUS_NOTIFICATION` と `SUBSCRIPTION_PERIOD_CHANGED_NOTIFICATION` の両方をサブスクライブする場合は、いずれかのコールバックを受信した後に `POST /api/v1/subscription/inquiry` を呼び出し、その最終照会結果にもとづいて単一のサブスクリプション処理フローを実行してください

## 高速な応答

* SDK はハンドラーの実行完了後に自動的に応答を構築します
* 時間のかかる処理 (メール送信、外部システムの更新など) は非同期で処理してください
* ハンドラー内で例外がスローされると、SDK は自動的に失敗応答を返します

## セキュリティ

* 必ず `X-SIGNATURE` を検証してください (SDK が自動で処理します)
* HTTPS エンドポイントを使用してください
* **イベントを処理する前に署名を検証してください**。検証が通る前にビジネスロジックを実行しないでください
* 応答には `X-SIGNATURE` ヘッダーを含めてください (SDK が自動で処理します)
