暗号資産チェックアウトはどのイベントを発行しますか?
InfraIO Payは状態遷移ごとに1つのwebhookを発火します。このステートマシンは意図的に小さく設計されており、フルフィルメントを正確に1つのイベントに紐付け、残りは無視できます。
- payment.pending、購入者がトランザクションをブロードキャストしました。確認はまだ積み上がっている途中です。
- payment.confirmed、トランザクションがそのネットワークの確認しきい値に到達しました。
- payment.settled、資金が決済用ウォレットにスイープされました。ここでフルフィルメントしてください。
- session.expired、チェックアウトウィンドウが支払いなしで終了しました。請求は発生しません。
どのイベントでフルフィルメントすべきですか?
payment.settledでフルフィルメントしてください。pendingのトランザクションは確認に失敗する可能性があり、確認しきい値はネットワークごとに異なるため、それより前の状態を最終確定として扱うと、決して到達しない決済に対して発送してしまうリスクがあります。settlementとは、その資金が取り消し不能にあなたのものになる時点です。
購入者に進行状況を見せる必要がある場合、UI上でpendingとconfirmedを表示しても構いませんが、取り消し不能なアクション(発送、アクセス付与、mint)は必ずsettledに紐付けてください。
webhookが本物であることをどう検証しますか?
すべてのwebhookはエンドポイントのシークレットで署名されています。raw requestボディ全体に対してHMACを再計算し、署名ヘッダーとconstant-timeで比較してください。一致しないものはすべて拒否します。HMACに不慣れな場合は、MDNのSubtleCrypto.signリファレンスが良い入門になり、StripeのWebhookベストプラクティスガイドは運用面をよく解説しています。
パースや処理の前に検証してください。署名がない、または署名が誤っているリクエストは、決してビジネスロジックに到達させてはいけません。
配信を安全にリトライできるようにするには?
Webhookはat-least-onceで配信されるため、ネットワークの一時的な不具合の後、同じイベントが複数回届くことがあります。各イベントにはidempotencyキーが付いています。処理済みのキーを記録し、繰り返しに対してはno-opにしてください。2xxを素早く返し、重い処理は非同期で行うことで、送信側がタイムアウトして不要なリトライをしないようにしましょう。InfraIOは配信ログを保持しており、意図的に再処理が必要な場合はワンクリックでreplayできます。