StripeのWebhookローカルテストを使えば、本番リリース前に決済イベントのハンドラを自分のマシンで検証できます。アプリをローカルで起動し、公開HTTPS URLで公開して、署名検証を完全に保ったまま実際のStripeテストモードイベントを受信します。
StripeのWebhookに公開URLが必要な理由
StripeはWebhookイベントを公開インターネット経由で、設定されたエンドポイントURLへ配信します。127.0.0.1:3000のようなアドレスはStripeのサーバーから到達できないため、ローカル開発には橋渡しが必要です。localhostトンネルは、ルーターやファイアウォールの変更なしに公開HTTPS URLをローカルプロセスにマッピングします。
テスト前に必要なもの
- テストモードのStripeアカウント。
- Webhookルート(例:
/api/webhooks/stripe)を持つローカルアプリ。 - 環境変数に設定したStripeのWebhook署名シークレット。
- 署名検証のためにリクエストヘッダーを保持するトンネルツール。
手順: PortPreviewでStripe Webhookをローカルテスト
- 対象ポートでアプリをローカル起動します。
npx portpreview 3000を実行して公開HTTPS URLを生成します。- Stripeダッシュボードの「開発者 → Webhook」でトンネルURLとWebhookパスを追加します。
- テストしたいイベント(例:
checkout.session.completed、invoice.paid)を選択します。 - ダッシュボードまたはCLIからテストイベントを送信し、各配信を確認します。
- ハンドラが2xxを返し、署名検証が通ることを確認します。
PortPreviewはヘッダー、ボディ、レスポンスステータスを記録するため、サーバーログだけから推測せずに失敗した配信をデバッグできます。
StripeのWebhook署名をローカルで検証する
開発中に署名検証を無効にしてはいけません。Stripeは各ペイロードをWebhookシークレットで署名するので、ハンドラは本番と同じようにStripe-Signatureヘッダーを検証すべきです。元のヘッダーを保持するトンネルツールなら、本物のコードパスをテストできます。
ローカルテストでよくある署名エラー:
- 間違ったWebhookシークレットの使用(ダッシュボードのシークレットとCLIのシークレットの取り違え)。
- 検証前にパース済みJSONボディを読んでしまい、生のリクエストボディを使っていない。
- Stripeの許容範囲を超えるクロックのずれ。
ローカルでテストする価値のあるイベント
Checkoutとサブスクリプション
checkout.session.completed、customer.subscription.created、invoice.payment_failedをテストして、プロビジョニング、アクセス付与、督促ロジックを確認します。
Connectとマーケットプレイスのフロー
Stripe Connectを使う場合は、本番前にテスト用の接続アカウントでアカウント更新イベントと送金通知を検証します。
冪等性とリトライ
Stripeは失敗した配信をリトライします。Webhookのリプレイを使って、ハンドラが重複イベントを安全に処理することを確認しましょう。
Stripe CLI vs localhostトンネル
Stripe CLIはstripe listen --forward-toでイベントを転送でき、手早い確認に適しています。localhostトンネルは、ダッシュボードに貼り付けたり、チームと共有したり、Stripe以外の複数プロバイダーでも使える安定した公開URLを提供します。多くのチームは両方を使い分けます。素早い反復にはCLI、本番設定を再現する統合テストにはトンネルです。
ローカルからステージングへ移すタイミング
ローカルテストはハンドラのロジック、ペイロードのパース、署名検証をカバーします。マネージドシークレット、DBマイグレーション、エンドツーエンドのリリースパイプラインなど環境固有の確認はステージングで行います。日々の決済機能の開発では、ローカルでのStripe Webhookテストが反復時間を数分から数秒に短縮します。
Webhookをローカルでデバッグする完全ガイドを読むか、Webhook中心のトンネルワークフローのためにPortPreviewのウェイトリストに登録してください。
