webhookが一向に届かないとき

順番に確認してください - 配信ログ、イベント名、ファイアウォール、署名の順です。Deliveriesタブを見れば、Diditが送信したかどうかがすぐにわかり、問題を半分に絞り込めます。

Short answer

まず送信先のDeliveriesタブを確認してください。Diditが一度も配信を試みていなければ、購読設定か送信先の問題です。試みたのに失敗している場合は、レスポンスコードで原因がわかります。404は、そのURLで自社のルートに到達できなかったことを意味し、署名の不一致は誤ったバイト列でハッシュを計算していることを意味します。

#ステップ1:Diditは送信を試みたか

API & Webhooksで送信先を開き、Deliveriesタブを確認します。すべての試行が個別にログとして記録され、レスポンスとともに表示されます。

送信先ごとの配信ステータスを表示するDiditコンソールのwebhookページ
  1. Last sentを見れば、Diditがそもそも送信を試みたかどうかがわかります。
  2. View statsで、その送信先の試行数と失敗数が表示されます。
  3. テスト送信を行えば、自社のエンドポイントとイベント自体の問題を切り分けられます。
  4. 失敗し続ける送信先は、修正するまで無効化できます。
欠落したイベントと失敗しているエンドポイントを区別するために必要な情報はすべてこのページにあります。

このひとつの確認だけで、問題を半分に絞り込めます。

  • 試行ログがない → その送信先向けのイベントが一度も生成されていません。ステップ2に進んでください。
  • 試行ログがあり、失敗している → Diditは送信し、あなたの側で拒否したか受信できなかったことになります。ステップ3に進んでください。
  • 試行ログがあり、2xx → 正常に配信されています。問題は配信ではなく、自社のハンドラー内にあります。

#ステップ2:試行ログがない場合

可能性が高い順に挙げます。

  1. そのイベントが購読されていない。 ワイルドカードは存在せず、すべてのイベントファミリーを明示的にリストアップする必要があります。存在しない名前(session.status.updatedkyc.completedなど)を指定すると、何も届かないまま黙って終わります。イベント一覧と照合してください。
  2. アプリケーションが違う。 送信先はアプリケーションに属しています。セッションが送信先とは別のアプリケーションで動いている場合、イベントが届くことは決してありません。設定が正しく見えるのに動かない場合の、最もよくある原因です。
  3. 実際には何も変わっていない。 webhookは変化があったときに発火します。動いていないセッションや、閾値を超える結果がなかったAML継続モニタリングの再スクリーニングは、正しくイベントを生成しません。
  4. 待っているステータスがまだ発生していない。 In Progressのセッションはまだ完了していません。セッションが終わらないときをご覧ください。

#ステップ3:配信が試みられて失敗した場合

404は、リクエストは届いたがそのルートが存在しなかったことを意味します。以下を確認してください。

  • 末尾のスラッシュを含む正確なパス。/hook/hook/にリダイレクトするフレームワークは、動作するはずのエンドポイントを404や本文の欠落に変えてしまうことがあります。
  • URLが公開されているかどうか。インターネットから到達できないローカルやステージングのホストは、この形で失敗します。
  • 自社アプリの手前にあるプロキシ、ロードバランサー、パスベースのルーターが、そのパスを別の場所に送っていないか。

5xxは、自社のハンドラーが例外を投げたことを意味します。パースする前に生の本文をログに残せば、実際に何を受信したかを確認できます。

タイムアウトは、応答が十分速くなかったことを意味します。まず2xxを返し、処理はその後に行ってください。

何も起きない・接続拒否は、自社のエッジがブロックしたことを意味します。Diditは静的IPの18.203.201.92から、DiditWebhook/2.0というユーザーエージェントで配信します。Cloudflareやデフォルト拒否のWAFの背後にいる場合は、受信ホスト名についてそのIPを許可してください。

#よくあるパターン:自動配信は404になるがResendは成功する

これはよく起きるので、名前を付けておく価値があります。自動配信は404で失敗するのに、同じイベントでResendをクリックすると成功します。

この組み合わせは、ペイロードとエンドポイントの両方に問題がないことを意味します。つまり違いは内容ではなくタイミングやパスにあります。以下を確認してください。

  • 元の配信の瞬間にデプロイや再起動が発生していなかったか。アプリが再び稼働状態になっているため、Resendは後で成功します。
  • プラットフォームのタイムアウトを超えたコールドスタート。サーバーレスで最初の呼び出しが遅い場合によく見られます。
  • 2回の試行の間でパスベースのルーティングが変わった、あるいは一部のリクエストにしか一致しないルールがあった。
  • 手動の再送は単発で届いたために通過した、自社エッジでのレート制限やボット対策

Deliveriesタブには両方の試行がタイムスタンプ付きで記録されているので、その時刻の自社のデプロイログやエラーログと突き合わせてください。

#署名検証が失敗する

ほぼ次の3つのいずれかです。

  1. 再シリアライズされたJSONでハッシュを計算している。 HMACは受信した生のリクエスト本文のバイト列そのものに対して計算してください。パースして再び文字列化すると空白やキーの順序が変わり、署名が一致しなくなります。多くのフレームワークでは、生の本文を得るために明示的な設定が必要です。
  2. シークレットが違う。 署名用シークレットは送信先ごとに異なり、APIキーとは別物です。2つの送信先には2つの異なるシークレットがあります。
  3. エンコーディングの前提が違う。 シークレットをリテラル文字列として使うのか、デコードしてから使うのか不明な場合は推測せず、署名検証のリファレンスを正確に確認し、デバッグ中は生の本文をログに残して比較できるようにしてください。
Important

署名の不一致を検証のスキップで「直す」ことは絶対にしないでください。検証されていないwebhookエンドポイントは、そのURLを見つけた誰からの偽の承認でも受け入れてしまい、デバッグ用の近道がアカウント乗っ取りの経路に変わってしまいます。

#2回のリトライはキューではない

5xx、404、タイムアウト、または接続失敗の場合、Diditは2回リトライします - おおよそ1分後、そしてその4分後です - その後は配信を打ち切ります。自社のエンドポイントがそれより長くダウンしていた場合、それらのイベントは完全に失われます。

整合性を取るための仕組みを用意してください。起動時に、確定ステータスを持っていないセッションについて判定エンドポイントをポーリングします。webhookは高速な経路として、ポーリングは保険として扱ってください。

#検証を実行せずにテストする

送信先ページのTry Webhookは、選んだ種類の完全な形のイベントを送信します - 承認、拒否、審査中、KYB、エンティティ、トランザクションなどです。実際のセッションがそれに依存する前に、自社のエンドポイント、署名チェック、ハンドラーが正しく動くことを確認するために使ってください。

サンドボックスはこのもう半分を担います。サンドボックスセッションは"environment": "sandbox"を持つ本物のwebhookを発行するため、経路全体を無料でエンドツーエンドに検証できます。サンドボックスでのテストをご覧ください。