Webhook のベストプラクティス
すばやく応答し、処理はあとで行う
Section titled “すばやく応答し、処理はあとで行う”署名を検証し、イベントをキューに入れて(データベースの行、キュー、バックグラウンドジョブ)、すぐに 2xx を返します。SpacePost が待つのは最大 15 秒で、遅いハンドラーは再試行と重複につながります。
配信は少なくとも 1 回です。処理した配信の webhook-id を保存し(一意制約で十分です)、重複はスキップしてください。
const inserted = await db.insert(processedWebhooks).values({ id: webhookId }).onConflictDoNothing().returning();if (inserted.length === 0) return new Response("duplicate", { status: 200 });必ず署名を検証する
Section titled “必ず署名を検証する”生のボディを使い、5 分より古いタイムスタンプは拒否し、署名は定数時間で比較します(SDK とライブラリが行います)。署名の検証をご覧ください。
順序を信用しない
Section titled “順序を信用しない”イベントは、特に再試行のあとに、順序が入れ替わって届くことがあります。ペイロードの created_at を保存済みの値と比較し、状態が前に進む変更だけを適用してください。SpacePost 自身の last_event も同じルールに従っています。
重要なイベントに対応する
Section titled “重要なイベントに対応する”| イベント | 典型的な対応 |
|---|---|
email.bounced |
データベースでそのアドレスを無効としてマークし、送信をやめます。 |
email.complained |
不可欠ではないメールの配信を、そのユーザーについてすぐに停止します。 |
email.delivery_delayed |
通常は何もしません。パスワードのリセットのように時間が重要なメールの場合は、アラートを出します。 |
email.failed |
data.failed.reason をログに記録してアラートを出し、必要に応じて修正のうえ再試行します。 |
email.suppressed |
宛先が送信停止リストに載っていました。管理画面に表示します。 |
処理するイベントだけを購読してください。イベントが少ないほど、通信量も失敗も減ります。
エンドポイントを保護する
Section titled “エンドポイントを保護する”- 有効な証明書を使って HTTPS で提供します。
- シークレットや、個人情報を含むペイロード全体をログに残さないでください。
- 他の動作を持たない専用のパスを使い、汎用的なボディを返します。
signing_secretは、ソース管理ではなくシークレットマネージャーに保管します。
ダッシュボードの配信ログを確認するか、繰り返される失敗にアラートを設定してください。エンドポイントが約 27 時間以上ダウンすると、すべての再試行を使い切ります。その後は手動で再送する必要があります。