Stripe Webhookとは?仕組みの基本とPAY.JPとの検証方法の違いを解説

2026.08.31

Stripe Webhook(ウェブフック)という言葉を見聞きしても、「そもそもWebhookとは何なのか」がいまひとつピンとこない方も多いのではないでしょうか。

この記事では、Webhookの考え方を概念レベルで整理し、Stripeでの基本的な使い方と、国内の決済API「PAY.JP」との違いを解説します。具体的なコードの書き方は各社の技術ドキュメントを参照いただくこととし、この記事では「そもそも何のためにあり、何に気をつけるべきか」を理解することを目的にしています。

この記事でわかること

  • そもそもWebhookとは何か、なぜ決済にWebhookが必要なのか
  • Stripeでの基本的な実装の流れと、実装時によく話題になるポイント
  • PAY.JPとの違い(検証方法・再送の仕組み)

そもそもWebhookとは?なぜ必要なのか

Webhookとは、何らかのイベントが起きたときに、相手のサービス側のシステムから、自社の指定したURLへ自動的に通知(HTTPリクエスト)が送られてくる仕組みです。ここでいう「相手のサービス」とはStripeのような決済サービスのこと、「自社」とは決済を導入している事業者側のシステムのことを指します。

Webhookは決済に限らず様々なサービスで使われている汎用的な仕組みで、Stripeでも「決済が成功した」「返金が完了した」「顧客情報が変更された」など、あらゆる種類のイベントに対応しています。特定の機能のためだけに用意された専用の仕組みではない、という点がまずポイントです。

その中でも、Webhookが特に必要とされる代表的な場面の一つが、サブスクリプションのような定期課金です。決済のAPIリクエストを送った直後に結果が返ってくる処理(その場でカードを通す等)であれば、レスポンスを見るだけで結果が分かります。

しかし、サブスクリプションの自動更新のように、購入者が何も操作していないタイミングで裏側で決済が実行される場合や、3Dセキュア認証のように途中で購入者の追加操作が挟まる場合は、自社のプログラムが「いつ」「どうなったか」を能動的に知るきっかけがありません。Webhookは、こうした非同期(時間差)で発生する結果を、後から自動的に受け取るための仕組みです。

Stripeでの基本的な使い方

Stripeでの実装は、大まかに次の流れになります。

  1. 受け取り用のエンドポイントを用意する:エンドポイントとは、外部からのリクエストを受け取れるように公開したURLのことです。Stripeが通知を送りつける宛先として、このURLを自社サーバー側に用意しておく必要があります
  2. Stripeのダッシュボードでエンドポイントを登録する:作成したURLと、受け取りたいイベントの種類を設定する。イベントとは、「決済が成功した」「返金が完了した」といった、Stripe側で起きた出来事を表すデータのことです
  3. 署名シークレットを使って、届いたリクエストを検証する:署名シークレットとは、Stripeと自社だけが知っている秘密の値のことです。これを使って、届いたリクエストが本物のStripeから送られたものか(第三者によるなりすましではないか)を確認します
  4. イベントの種類ごとに処理を行い、すぐに200のレスポンスを返す:受け取った内容に応じて必要な処理(決済成功ならDBの更新など)を自社サーバー側で行い、そのうえで自社サーバーからStripeに対して200を返します。200とはHTTPのステータスコード(通信の結果を表す数字)の一つで、「正常に受け取り、処理できました」という意味を表します
  5. テストツールで一連の動作を確認する:200が返せることだけでは実装完了とは言えません。「たまたま空の処理で200を返しただけ」なのか「実際に狙った処理が動いた上での200」なのかを区別する必要があるためです。Stripe CLIのstripe listenコマンドでローカル環境にイベントを転送し、stripe trigger payment_intent.succeededのように実際のイベントを疑似的に発生させて、①署名検証が正しく通る②想定した処理(DBの更新等)が実際に動く③200が返り、Stripeのダッシュボード上で「配信成功」と表示される、の3点を確認できて初めて実装完了と言えます

Node.jsでの最小限の実装イメージは次の通りです(Stripe公式のWebhookクイックスタートより)。

12345678910111213
app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
 const signature = request.headers['stripe-signature'];
 let event;
 try {
   event = stripe.webhooks.constructEvent(request.body, signature, endpointSecret);
 } catch (err) {
   return response.sendStatus(400); // 検証に失敗した場合は拒否する
 }
 if (event.type === 'payment_intent.succeeded') {
   // 決済成功時の処理をここに書く
 }
 response.send(); // 200レスポンスをすぐ返す
});

ここで行っているconstructEventが、先ほど触れた「署名の検証」の具体的な処理です。届いたデータ・タイムスタンプ・署名シークレットを使ってハッシュ値を計算し、リクエストに含まれるStripe-Signatureヘッダーの値と一致するか確認します。これにより、悪意のある第三者が偽の通知を送りつけてきた場合に、それを見分けて拒否できます。

実装時によく話題になるポイント

具体的な対処法はドキュメントに譲りますが、Stripeは通知を確実に届けるため、配信に失敗した場合は間隔を空けながら自動的に再送を試みる仕組みになっています。ここで注意したいのが、時間のかかる処理を先に済ませてからレスポンスを返すと、実際には受信できていてもStripe側がタイムアウトと判断し、同じ通知を再送してしまう点です。そのため重い処理は後回しにしてまず素早く200を返すのが基本です。

また、この再送によって同じ通知が複数回届くことがあるため、イベントごとのIDを記録し、処理済みのものは無視する仕組みも用意しておく必要があります。

PAY.JPで実装する場合、Stripeと何が違うのか

国内の決済サービスPAY.JPにも、Stripeと同じ考え方のWebhook機能があります(v1のWebhookv2のイベントとWebhookとしてそれぞれドキュメントが用意されています)。決済・顧客・返金といったイベントが発生するたびに、指定したURLへ通知が送られてくる点は共通です。

なお、PAY.JPでは、サブスクリプションの状態確認のようにWebhookを使わずAPIへの問い合わせだけで完結できる場面もありますが、返金や不正検知など他のイベントも扱いたい場合や、ポーリング(一定間隔でAPIに問い合わせて最新の状態を確認する方法)より効率的にリアルタイムで検知したい場合は、PAY.JPでもWebhookを選んで使う開発者が多いのが実情です。ここでは、実際にWebhookを使う場合の検証方法・再送の仕組みの違いを解説します。

「届いた通知が本物かどうかをどう確認するか」という検証方法には、次のような違いがあります。

  • Stripe:前述の通り、署名シークレットを使ってハッシュ値を計算し、リクエストの中身が改ざんされていないかまで確認する「署名検証」の仕組み
  • PAY.JP:X-Payjp-Webhook-Tokenというヘッダーに、アカウントごとに割り当てられた固定のトークンIDが含まれており、これがあらかじめ控えておいた値と一致するかを確認する仕組み

署名検証は、リクエストの中身(金額やイベント内容)が送信後に改ざんされていないかまで検証できる仕組みです。一方PAY.JPの固定トークン方式は、送信元がPAY.JPかどうかを確認することに絞った仕組みで、中身の改ざん検知までは行っていません。優劣というより、検証の対象範囲が異なる仕組みだと理解しておくとよいでしょう。

再送(リトライ)の仕組みにも違いがあります。Stripeは配信に失敗した場合、本番環境で最長3日間、間隔を空けながら再送を試みます。一方PAY.JPは、配信に失敗した場合(2xx=200番台(200はその一つ)以外のステータスコードが返ってきた場合・10秒のタイムアウト・接続エラー時)に3分間隔で最大3回(合計9分程度)まで再送する仕様です(イベントとWebhook)。自社サーバーのメンテナンス等でこの時間より長く受け取れない状態が続くと、PAY.JPでは通知を取りこぼす可能性がある点は覚えておくとよいでしょう。

Stripe決済の全体像についてはStripeとは?決済プラットフォームの仕組み・機能・手数料でも解説しています。

まとめ

  • Webhookとは、決済・返金・顧客情報の変更などのイベントが起きた際に、相手のサービス側から自社へ自動的に通知が送られてくる汎用的な仕組み。サブスクリプションの自動更新のように、非同期で発生する結果を検知したい場面で特によく使われる
  • Stripeでの実装は、エンドポイント用意→ダッシュボードで登録→署名検証→200レスポンス→テストツールでの動作確認、という流れが基本。200を返せることだけでなく、狙った処理が実際に動くことをテストツールで確認できて初めて実装完了と言える
  • Stripeは配信を保証するため自動的に再送を行う仕組みがあり、それに伴い「素早く200を返す」「重複イベントに対応する」という2点に気をつける必要がある
  • PAY.JPにも同様のWebhook機能があるが、検証方法(Stripe:署名計算による改ざん検知/PAY.JP:固定トークンの一致確認)とリトライ期間(Stripe:最長3日間/PAY.JP:3分間隔で最大3回)が異なる
  • PAY.JPのWebhookを実際に試してみたい方はPAY.JPのサービスページも確認してみてください

執筆者

PAY.JP編集部

PAY.JPを運営するPAY株式会社の編集部。決済・Fintech・SaaSビジネスに関する情報を、事業者・開発者向けにわかりやすく発信しています。