Webhookの設計で気をつけたいポイント

目次

Webhookは「外部から呼ばれる入口」

Webhookは、外部サービスで何かイベントが起きたときに、自分たちのシステムへHTTPリクエストを送ってもらう仕組みです。

たとえば、決済サービスで支払いが完了したとき、チャットツールにメッセージが投稿されたとき、ECサイトで注文が作成されたときなどに、「イベントが発生しましたよ」と別のシステムへ通知するために使われます。

APIが「こちらから情報を取りに行く仕組み」だとすると、Webhookは「相手から情報を届けてもらう仕組み」と考えるとわかりやすいです。

たとえば宅配便に例えるなら、APIは自分で配送状況を何度も確認しに行くイメージです。一方Webhookは、荷物が届いたタイミングでインターホンが鳴るようなものです。必要なタイミングで通知が届くため、無駄な確認処理を減らせるのが大きなメリットです。

ただし、Webhookは便利な反面、設計を雑にしてしまうとトラブルの原因になりやすい仕組みでもあります。外部サービスから突然リクエストが届くため、受け取り方、認証、再送、重複処理、障害時の対応などをきちんと考えておく必要があります。

この記事では、Webhookを設計するときに気をつけたいポイントを、わかりやすいように整理していきます。

Webhookの基本的な流れ

Webhookの基本的な流れは、それほど難しくありません。

まず、通知を送る側のサービスでイベントが発生します。たとえば「支払いが完了した」「ユーザーが登録された」「ファイルがアップロードされた」といった出来事です。

次に、そのサービスが事前に登録されたURLへHTTPリクエストを送ります。このURLがWebhookの受け口になります。多くの場合、POSTメソッドでJSON形式のデータが送られてきます。

最後に、受け取った側のシステムが内容を確認し、必要な処理を行います。注文情報を更新したり、メールを送ったり、社内通知を出したりするわけです。

簡単なイメージは次のようになります。

外部サービスでイベント発生
  ↓
Webhook URLへ通知
  ↓
自分たちのシステムで受信
  ↓
内容を確認して処理

見た目はシンプルですが、実務では「本当にそのサービスから送られてきた通知なのか」「同じ通知が何度も届いたらどうするのか」「受信後の処理に時間がかかったらどうするのか」といった点が重要になります。

Webhookは単なるHTTPリクエストではありますが、システム間連携の入口になるため、通常のAPIよりも慎重に設計したい部分があります。

Webhook設計で最初に考えるべきこと

何のイベントを受け取るのかを明確にする

Webhookを設計するときは、まず「どのイベントを受け取るのか」を明確にします。

外部サービスによっては、たくさんの種類のイベントを送れることがあります。たとえば決済サービスなら、支払い完了、支払い失敗、返金、サブスクリプション更新、解約など、さまざまなイベントがあります。

ここで何でもかんでも受け取るようにすると、後から処理が複雑になりがちです。必要なイベントだけを選び、それぞれのイベントで何をするのかを決めておくことが大切です。

たとえば「支払い完了」のWebhookを受け取るなら、システム側では注文ステータスを「支払い済み」に更新するのか、ユーザーへメールを送るのか、管理画面に反映するのか、といった処理内容を整理しておきます。

イベント名だけを見て実装を始めるのではなく、「そのイベントを受け取った後、業務上どんな状態にしたいのか」まで考えると、設計がぶれにくくなります。

受け取るデータの形を把握する

Webhookでは、イベントの種類だけでなく、送られてくるデータの中身も重要です。

JSONで送られてくる場合、次のような情報が含まれることがあります。

{
  "event": "payment.completed",
  "id": "evt_123",
  "created_at": "2026-05-01T10:00:00Z",
  "data": {
    "order_id": "order_456",
    "amount": 3000,
    "currency": "JPY"
  }
}

この例では、イベント名、イベントID、作成日時、注文ID、金額、通貨などが含まれています。

設計時には、どの項目を信頼して使うのか、どの項目は保存しておくのか、どの項目が必須なのかを確認しておきます。特にイベントIDは、後で説明する重複処理の対策として重要になることが多いです。

また、外部サービスの仕様変更にも注意が必要です。Webhookのペイロードに新しい項目が追加されることは珍しくありません。そのため、知らない項目が増えても処理が壊れないようにしておくと安心です。

認証と検証を必ず入れる

Webhookは誰でも叩けるURLになりやすい

Webhookの受信URLは、インターネット上からアクセスできる場所に置かれることが多いです。つまり、URLを知っていれば、外部サービス以外の誰かがリクエストを送ってくる可能性があります。

そのため、「リクエストが来たから正しい通知だ」と考えるのは危険です。Webhookでは、送信元が本物かどうかを確認する仕組みが必要です。

代表的な方法としては、署名検証があります。

署名検証では、送信側サービスと受信側システムで共通の秘密鍵を使います。送信側はリクエスト本文などをもとに署名を作り、HTTPヘッダーに付けて送信します。受信側は同じ方法で署名を計算し、送られてきた署名と一致するかを確認します。

ざっくり言うと、「この封筒は本当に信頼できる相手から届いたものか」を封印で確認するようなイメージです。

署名検証はなるべく最初に行う

Webhookを受け取ったら、まず署名検証を行うのが基本です。

署名が不正なリクエストに対して、データベース更新やメール送信などの処理をしてはいけません。怪しいリクエストは早い段階で拒否します。

処理の流れとしては、次のような形がわかりやすいです。

Webhook受信
  ↓
署名を検証
  ↓
不正なら処理せず終了
  ↓
正しければイベント内容を確認
  ↓
必要な処理を実行

ここで注意したいのは、署名検証の方法はサービスごとに異なるということです。ヘッダー名、署名の計算方法、タイムスタンプの扱いなどは、利用しているサービスのドキュメントに従う必要があります。

また、秘密鍵はコードに直接書かず、環境変数やシークレット管理の仕組みを使って管理するのが安全です。

再送される前提で設計する

Webhookは失敗すると再送されることがある

Webhookでは、受信側がエラーを返したり、一定時間内に応答しなかったりすると、送信側サービスが同じイベントを再送することがあります。

これは便利な仕組みです。たとえば一時的にサーバーが不安定だった場合でも、再送によって処理をやり直せる可能性があります。

ただし、再送があるということは、同じ通知が複数回届く可能性があるということでもあります。

ここを考慮せずに実装すると、同じ注文を何度も処理してしまったり、同じメールを何通も送ってしまったり、同じポイントを二重に付与してしまったりすることがあります。

Webhook設計では、「同じイベントが複数回来ても問題ない状態」を作ることがとても大切です。

冪等性を意識する

同じ処理を何度実行しても結果が変わらない性質を、冪等性と呼びます。少し難しい言葉ですが、Webhookではかなり重要な考え方です。

たとえば、支払い完了イベントを受け取ったとします。

悪い例は、Webhookを受け取るたびに「売上を加算する」「ポイントを付与する」「メールを送る」といった処理を無条件で実行することです。同じイベントが2回届いたら、処理も2回走ってしまいます。

良い例は、イベントIDや注文IDを確認し、「このイベントはすでに処理済みか」を見てから処理することです。処理済みであれば何もしない、まだであれば処理して記録する。この流れにしておくと、再送に強くなります。

イベントIDを確認
  ↓
処理済みならスキップ
  ↓
未処理なら処理を実行
  ↓
処理済みとして記録

実務では、Webhookイベントを保存するテーブルを用意し、イベントIDにユニーク制約を付ける方法がよく使われます。これにより、同じイベントIDを二重に登録できないようにできます。

応答はできるだけ早く返す

Webhookの受信処理で重い処理をしすぎない

Webhookを受け取ったとき、ついその場で全部の処理を終わらせたくなります。

たとえば、データベース更新、外部API呼び出し、メール送信、PDF生成、チャット通知などを一気に実行するような実装です。

しかし、Webhookの受信処理で重い処理をしすぎると、応答が遅くなります。送信側サービスは一定時間内に成功レスポンスが返ってこないと失敗と判断し、再送することがあります。その結果、処理が重複したり、システム全体が不安定になったりします。

Webhookの受信口では、まずリクエストを検証し、必要最低限の情報を保存し、できるだけ早く成功レスポンスを返す設計が扱いやすいです。

重い処理は、キューやバックグラウンドジョブに渡して非同期で実行すると安定します。

Webhook受信
  ↓
署名検証
  ↓
イベントを保存
  ↓
すぐに200 OKを返す
  ↓
別処理でイベントを処理

この形にしておくと、Webhookの受信部分と実際の業務処理を分けられます。障害時の原因調査もしやすくなり、再実行もしやすくなります。

200 OKを返すタイミングに注意する

早く応答を返すことは大切ですが、何も確認せずに200 OKを返せばよいわけではありません。

少なくとも、署名検証や最低限の形式チェックは行ったうえで成功レスポンスを返すのが安全です。不正な通知まで成功扱いにしてしまうと、後から原因を追いにくくなります。

一方で、メール送信や外部API連携の完了まで待ってから200 OKを返すと、タイムアウトしやすくなります。

つまり、Webhook受信時に行う処理と、後で行う処理の線引きが重要です。

受信時にやることは、本人確認、形式確認、イベント保存。後でやることは、業務処理、通知、外部連携。こう分けておくと設計がすっきりします。

イベントの順序に依存しすぎない

Webhookは必ず順番通り届くとは限らない

Webhookでよくある落とし穴が、イベントの到着順序です。

たとえば、本来は「注文作成」イベントの後に「支払い完了」イベントが発生したとしても、ネットワークや送信側の都合により、受信側では「支払い完了」が先に届くことがあります。

また、あるイベントが再送された結果、古いイベントが後から届くこともあります。

そのため、Webhookの処理では「必ず順番通りに届く」と決めつけないほうが安全です。

現在の状態を確認して処理する

イベントを受け取ったら、そのイベントだけを見て処理を決めるのではなく、現在のシステム上の状態も確認すると安全です。

たとえば、注文のステータスがすでに「キャンセル済み」なのに、古い「支払い完了」イベントが届いた場合、単純に「支払い済み」へ戻してしまうとおかしな状態になります。

このようなケースでは、状態遷移のルールを決めておくことが大切です。

たとえば次のような考え方です。

未払い → 支払い済み はOK
支払い済み → 発送準備中 はOK
キャンセル済み → 支払い済み は基本NG

Webhookは「イベントの通知」であって、「必ずその通りに状態を変えなければならない命令」ではありません。受信側のシステムが、現在の状態と照らし合わせて判断する必要があります。

エラー時の扱いを決めておく

どのエラーで再送させるか

Webhookでは、受信側がどのHTTPステータスコードを返すかによって、送信側サービスの動きが変わることがあります。

一般的には、正常に受け取れた場合は2xx系のステータスを返します。エラーの場合は4xxや5xxを返します。

ただし、何でも5xxを返せばよいわけではありません。

たとえば署名が不正なリクエストは、何度再送されても正しく処理できません。この場合は400系のエラーとして扱うことが多いです。

一方で、データベースに一時的につながらない、内部処理で一時的な障害が発生した、といったケースでは、再送によって復旧できる可能性があります。このような場合は5xx系を返す判断もあります。

大切なのは、エラーの種類ごとに扱いを決めておくことです。

ログを必ず残す

Webhookのトラブル調査では、ログがとても重要です。

外部サービスから「通知は送った」と言われても、受信側に記録がなければ何が起きたのか追えません。逆に、受信側にイベントID、受信時刻、ステータス、処理結果が残っていれば、かなり調査しやすくなります。

最低限、次のような情報は記録しておくと便利です。

  • イベントID
  • イベント種別
  • 受信日時
  • 処理ステータス
  • エラー内容
  • 関連する注文IDやユーザーID

ただし、ログに個人情報や機密情報をそのまま残しすぎるのは避けたいところです。必要な情報は残しつつ、クレジットカード番号やトークンのような機密性の高い値は保存しない、またはマスクするようにします。

セキュリティ面で気をつけたいこと

HTTPSは必須と考える

Webhookの受信URLは、基本的にHTTPSにします。

HTTPのままだと、通信内容が盗み見られたり、改ざんされたりするリスクがあります。Webhookには注文情報やユーザー情報など、重要なデータが含まれることもあるため、暗号化された通信を使うのが前提です。

多くの外部サービスでは、Webhook URLとしてHTTPSしか登録できない場合もあります。ローカル開発時はトンネリングツールなどを使うことがありますが、本番環境では正しい証明書を使ったHTTPS構成にしましょう。

IP制限だけに頼りすぎない

送信元のIPアドレスを制限できる場合、それは有効な対策のひとつです。

ただし、IP制限だけに頼るのはおすすめしません。外部サービス側のIPアドレスが変更されることもありますし、クラウド環境では送信元の範囲が広いこともあります。

セキュリティ対策は、ひとつの方法に頼るよりも、複数の仕組みを組み合わせるほうが安全です。

たとえば、HTTPS、署名検証、必要に応じたIP制限、レート制限、ログ監視を組み合わせると、より堅牢になります。

リプレイ攻撃への対策も考える

リプレイ攻撃とは、過去に送られた正しいリクエストを第三者が再利用して、もう一度送ってくるような攻撃です。

署名が正しくても、過去のリクエストをそのまま再送されると困るケースがあります。

この対策として、タイムスタンプ付きの署名を検証する方法があります。受信側で「このリクエストは一定時間以内に作られたものか」を確認し、古すぎるリクエストは拒否します。

また、イベントIDを保存しておき、同じイベントIDを再処理しないようにすることも有効です。これは重複処理対策にもなります。

データ保存の考え方

生のWebhookデータを保存するか

Webhookを受け取ったとき、送られてきたJSONをそのまま保存するかどうかは、設計上の大事なポイントです。

生データを保存しておくと、後から「実際にどんな通知が来ていたのか」を確認できます。障害調査や再処理のときに役立ちます。

一方で、生データには不要な情報や個人情報が含まれることがあります。そのまま長期間保存すると、セキュリティや運用面での負担になります。

そのため、保存する場合は、保存期間、マスキング対象、アクセス権限を決めておくと安心です。

実務では、イベントID、イベント種別、関連ID、処理状態、必要なペイロードだけを保存し、生データは短期間だけ保持する、といった設計もよくあります。

処理ステータスを持たせる

Webhookイベントを保存する場合は、処理ステータスを持たせると運用しやすくなります。

たとえば、次のようなステータスです。

  • received: 受信済み
  • processing: 処理中
  • processed: 処理完了
  • failed: 処理失敗
  • ignored: 対象外として無視

ステータスがあると、管理画面やログから現在の状態を確認しやすくなります。失敗したイベントだけを再実行する、といった運用も可能になります。

Webhookは「受け取って終わり」ではなく、「受け取った後に正しく処理できたか」まで見る必要があります。そのため、処理状態を追える設計にしておくと、トラブルに強くなります。

実務で役立つ設計パターン

受信と処理を分ける

実務で特におすすめなのは、Webhookの受信処理と業務処理を分ける設計です。

受信側のエンドポイントでは、署名検証、簡単なバリデーション、イベント保存だけを行います。そして、保存したイベントをキューやジョブワーカーが後から処理します。

この設計にすると、外部サービスへの応答を早く返せます。また、業務処理で失敗しても、イベントを保存しているため再実行しやすくなります。

Webhookエンドポイント
  ↓
イベント保存
  ↓
ジョブキュー
  ↓
ワーカーが業務処理

規模が小さいうちは、必ずしも本格的なキューサービスを使う必要はありません。まずはデータベースにイベントを保存し、定期実行処理で未処理イベントを拾う形でも十分な場合があります。

大切なのは、WebhookのHTTPリクエスト中にすべてを完結させないことです。

手動再実行できる仕組みを用意する

Webhook処理は、外部サービスやネットワークの影響を受けます。そのため、どれだけ丁寧に作っても、失敗する可能性はあります。

失敗したときに手動で再実行できる仕組みがあると、運用がかなり楽になります。

たとえば、管理画面から失敗イベントを一覧表示し、必要に応じて再処理できるようにします。管理画面がない場合でも、管理用コマンドやスクリプトで再実行できるようにしておくと便利です。

ただし、再実行できるようにする場合も、冪等性は必須です。再実行によって二重処理が起きないように、処理済み判定やユニーク制約を入れておきます。

監視とアラートを入れる

Webhookは外部サービスとの連携点なので、止まっていても気づきにくいことがあります。

たとえば、Webhookの受信自体は成功しているけれど、内部処理が失敗し続けている。あるいは、そもそも外部サービスから通知が届かなくなっている。このような状態は、利用者から問い合わせが来て初めて発覚することもあります。

できれば、次のような観点で監視を入れておくと安心です。

  • Webhook受信数
  • 処理成功数
  • 処理失敗数
  • 処理待ち件数
  • 処理時間
  • 同一イベントの重複数

特に、失敗数が急に増えた場合や、処理待ち件数が増え続けている場合は、早めに気づけるようにしておきたいです。

ローカル開発とテストのポイント

ローカル環境で受信テストをする

Webhookは外部サービスからリクエストを受け取る仕組みなので、ローカル開発では少し工夫が必要です。

通常、自分のパソコン上で動いている開発サーバーには、外部サービスから直接アクセスできません。そのため、ローカル環境を一時的に外部公開するトンネリングツールを使うことがあります。

これにより、外部サービスからローカルのWebhookエンドポイントへリクエストを送れるようになります。

ただし、ローカル開発用のURLを本番設定に入れないように注意しましょう。開発用と本番用のWebhook URLは明確に分けて管理することが大切です。

テストデータと本番データを混ぜない

Webhookのテストでは、テスト環境と本番環境を分けることがとても重要です。

決済や注文などのWebhookでは、テスト用イベントと本番用イベントを混ぜると大きなトラブルにつながります。テストのつもりで送った通知が本番の注文処理に影響してしまうと困ります。

環境ごとに、Webhook URL、署名検証用の秘密鍵、データベース、外部サービスの設定を分けておきましょう。

また、イベントに「livemode」のような本番・テストを示す項目がある場合は、それも確認すると安全です。

異常系のテストも行う

Webhookのテストでは、正常に通知を受け取れるかだけでなく、異常系も確認しておきたいです。

たとえば、次のようなケースです。

  • 署名が不正なリクエスト
  • 必須項目が欠けているリクエスト
  • 同じイベントが2回届くケース
  • 古いイベントが後から届くケース
  • 内部処理が失敗するケース
  • 外部APIがタイムアウトするケース

正常系だけを見ると、実装は簡単に見えます。しかし、実際の運用で問題になるのは異常系のことが多いです。

最初からすべて完璧にテストするのは大変ですが、少なくとも重複、再送、署名不正、処理失敗は確認しておくと安心です。

実装時に意識したい小さな工夫

イベント種別ごとに処理を分ける

Webhookの処理では、イベント種別ごとに処理を分けると見通しがよくなります。

すべてのイベントをひとつの大きな関数で処理すると、条件分岐が増えて読みにくくなります。最初は問題なくても、イベント種類が増えると保守が大変です。

このようにイベント種別ごとに処理を切り出しておくと、後から機能追加しやすくなります。

  • payment.completed → 支払い完了処理
  • payment.failed → 支払い失敗処理
  • order.cancelled → 注文キャンセル処理

未対応イベントは安全に無視する

外部サービスによっては、こちらが想定していないイベントが届くことがあります。

そのとき、未対応イベントでエラーにするのか、無視するのかを決めておきましょう。多くの場合、未対応イベントはログを残して無視する設計が扱いやすいです。

ただし、重要なイベントを見落としている可能性もあるため、完全に何も残さず捨てるのは避けたほうがよいです。

「未対応イベントを受け取った」というログを残しておけば、後から仕様変更や設定ミスに気づけます。

タイムアウトを短めに考える

Webhook処理内で外部APIを呼ぶ場合は、タイムアウトにも注意が必要です。

外部APIの応答を長く待ちすぎると、Webhook全体の処理が詰まってしまいます。できれば、Webhook受信時には外部APIを直接呼ばず、非同期処理に回すのがおすすめです。

どうしても呼ぶ必要がある場合は、タイムアウトを設定し、失敗時の扱いを決めておきます。

「いつか返ってくるかもしれない」と待ち続ける設計は避けましょう。システムでは、失敗することを前提にしておくほうが安定します。

一問一答

WebhookとAPIの違いは何ですか?

APIは、基本的には自分たちのシステムから相手のシステムへ情報を取りに行く仕組みです。Webhookは、相手のシステムから自分たちのシステムへイベント通知を送ってもらう仕組みです。

「こちらから聞きに行く」のがAPI、「相手から知らせてもらう」のがWebhookと考えるとわかりやすいです。

Webhookの処理で一番気をつけることは何ですか?

実務では、認証、重複処理、再送対応が特に重要です。

Webhookは外部から届くため、まず本物の通知かを確認する必要があります。また、同じイベントが複数回来る可能性があるため、二重処理が起きないように設計することも大切です。

Webhookの受信処理ですぐ業務処理をしてもよいですか?

小さな処理であれば可能ですが、基本的には受信と業務処理を分けるのがおすすめです。

受信時には検証と保存だけを行い、重い処理はバックグラウンドで実行すると安定しやすくなります。外部サービスへの応答も早く返せるため、再送やタイムアウトのリスクを減らせます。

同じWebhookが何度も届いた場合はどうすればよいですか?

イベントIDなどを使って、すでに処理済みかどうかを確認します。処理済みであればスキップし、未処理であれば処理して記録します。

このように、同じイベントが複数回来ても結果が変わらないようにしておくことが大切です。

まとめ

Webhookは、外部サービスで発生したイベントをリアルタイムに近い形で受け取れる便利な仕組みです。APIのように何度も確認しに行かなくても、必要なタイミングで通知を受け取れるため、システム連携ではよく使われます。

一方で、Webhookは外部から呼ばれる入口でもあります。そのため、設計時にはセキュリティ、再送、重複、順序、障害時の対応をしっかり考える必要があります。

特に大切なのは、本物の通知かどうかを検証すること、同じイベントが複数回来ても問題ないようにすること、受信処理を軽くして早く応答を返すことです。

また、受け取ったイベントを保存し、処理ステータスを管理しておくと、障害時の調査や再実行がしやすくなります。Webhookは一度作って終わりではなく、運用しながら状態を確認できる設計にしておくことが重要です。

最初はシンプルな実装でもかまいません。ただし、署名検証、イベントIDによる重複防止、ログ保存、失敗時の再処理といった基本部分は、できるだけ早い段階で入れておきたいところです。

セキュリティ面をもう少し広く確認したい場合は、OWASP Top 10も参考になります。OWASP Top 10は、Webアプリケーションで注意すべき代表的なセキュリティリスクを整理したものです。Webhookの受信エンドポイントもWebアプリケーションの入口のひとつなので、認証やアクセス制御の不備、設定ミス、ログや監視の不足など、共通して気をつけたいポイントが多くあります。

Webhookだけを特別なものとして見るのではなく、「外部からアクセスされるWebアプリケーションの一部」として考えると、設計の抜け漏れを減らしやすくなります。署名検証や再送対策に加えて、OWASP Top 10のような観点もあわせて確認しておくと、より安心して運用できるWebhookになります。

Webhookは、うまく設計すればシステム同士をなめらかにつなぐ強力な仕組みになります。逆に、何となく受け取って何となく処理するだけだと、後からトラブルの原因になりやすいです。

外部から届く大事な通知を、どう安全に、どう確実に、どう運用しやすく扱うか

この視点を持って設計すると、Webhookはぐっと扱いやすくなります。実務でWebhookを実装するときは、単にエンドポイントを作るだけでなく、再送される前提、失敗する前提、後から調査する前提で考えてみてください。そうすることで、運用に強く、安心して使えるWebhook連携を作りやすくなります。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次