Webhook
うぇぶふっく
イベント発生時にサーバー側からHTTPで通知してもらう「逆向きのAPI」。ポーリングをなくす。
概要
Webhook は、「何かが起きたら、こちらの URL に HTTP リクエストを送って知らせてください」と相手のサービスに登録しておく仕組みです。通常の API 呼び出しは自分から相手に尋ねに行きますが、Webhook では矢印が逆になり、イベントが発生した瞬間に相手側のサーバーがこちらのエンドポイントを呼び出します。このため「逆向きの API」「HTTP コールバック」とも呼ばれます。
身近な例は至るところにあります。Stripe で決済が完了したら自社サーバーに通知が届く、GitHub に push されたら CI/CD が起動する、Slack にメッセージを自動投稿する — これらはすべて Webhook です。特別なプロトコルは不要で、受け側は「POST を受け取る普通の HTTP エンドポイント」を1つ用意するだけなので、サービス間連携の最も手軽な共通言語として定着しています。
なぜ生まれたか
Webhook 以前、外部サービスの変化を知る方法は「何度も聞きに行く」ポーリングだけでした。「新しい注文はある?」「まだ?」と数秒〜数分おきに API を叩き続けるのです。ほとんどの問い合わせは「変化なし」の空振りで、送る側にも受ける側にも無駄な負荷がかかります。かといって間隔を延ばせば、決済完了の反映が数分遅れるといった体験の悪化に直結します。API のレート制限(呼び出し回数の上限)に阻まれて、そもそも十分な頻度で聞けないことも珍しくありません。
そこで発想を反転させ、「変化を知りたい側が聞き続ける」のではなく「変化が起きた側がその瞬間に知らせる」ようにしたのが Webhook です。イベントが起きたときだけ通信が発生するため、無駄な往復が消え、遅延はほぼゼロになります。2007年頃にこのパターンに Webhook という名前が付き、REST API の普及とともに「API を提供するなら Webhook もセットで」という形で広まりました。
詳細
基本の流れ
使い方はどのサービスでもほぼ共通です。まず外部サービスの管理画面や API で、通知先 URL と受け取りたいイベントの種類(例: 決済完了、push、issue 作成)を登録します。以降、該当イベントが発生するたびに、外部サービスがその URL へ POST リクエストを送ってきます。ボディはイベントの内容を表す JSON が一般的です。受け側は内容を処理し、HTTP 200 番台を返して「受け取った」と伝えます。この応答が、次に述べる再送の判断材料になります。
署名検証 — 誰でも叩けるURLを守る
Webhook の受信エンドポイントは、インターネットに公開された「誰でも POST できる URL」です。何もしなければ、攻撃者が偽の「決済完了」通知を送りつけることも可能です。そこで多くのサービスは、送信時にペイロードと共有シークレットから HMAC というハッシュベースの署名を計算し、ヘッダに付与します(Stripe の Stripe-Signature、GitHub の X-Hub-Signature-256 など)。受け側は同じ計算をして一致を確認することで、正規の送信元であること(なりすまし防止)と、内容が途中で書き換えられていないこと(改ざん防止)を同時に検証できます。署名にタイムスタンプを含めて、傍受したリクエストを後から再送するリプレイ攻撃を防ぐ設計も一般的です。「Webhook を受けるなら署名検証は必須」と覚えてください。もちろん受信 URL は HTTPS にします。
再送と冪等性 — 「少なくとも1回」を前提に設計する
ネットワークやサーバーの不調で通知が届かないことは避けられないため、送信側はエラー応答やタイムアウトのとき、間隔を空けながら何度か再送します。ここで重要なのは、この保証が「少なくとも1回(at-least-once)」であることです。処理は成功したのに応答が届かなかった場合、同じ通知がもう一度届きます。つまり受け側は「同じイベントが2回来ても壊れない」ように作る必要があり、これが冪等性です。実務では、通知に含まれるイベント ID を記録しておき、処理済みの ID なら何もせず 200 を返す、という重複排除が定石です。
受け側の設計 — すぐ返して、あとで処理する
もう1つの定石が非同期化です。Webhook の送信側は応答を数秒しか待たないことが多く、受けたその場で重い処理(DB 更新、メール送信、外部 API 呼び出し)をすると、タイムアウト → 再送 → さらに負荷増、という悪循環に陥ります。そこで受信ハンドラでは署名検証とイベントのメッセージキューへの投入だけを行って即座に 200 を返し、実際の処理はワーカーが非同期で行う構成が推奨されます。イベントの集中(決済サービスの障害復旧後に溜まった通知が一斉に届く、など)に対する緩衝材としてもキューが効きます。
開発時の工夫と実例
開発中のローカルマシンは外部から到達できないため、Webhook のテストには ngrok や Cloudflare Tunnel のようなトンネリングツールで一時的な公開 URL を作り、手元のサーバーへ転送するのが定番です。Stripe CLI のように、イベントをローカルへ転送・再現する専用ツールを提供するサービスもあります。
実例を挙げると、決済(Stripe・PayPal の入金/失敗通知)、開発フロー(GitHub の push を契機に CI/CD を起動)、チャット連携(Slack・Discord の Incoming Webhook)、SaaS 間自動化(Zapier や IFTTT の裏側)など、現代のサービス連携の大半は Webhook で駆動されています。なお Webhook はサーバー間の通知であり、ブラウザへのプッシュには SSE や WebSocket を使う、という住み分けも押さえておくと整理しやすいでしょう。