ローカルホストで PayPal サンドボックス Webhook をテストするには、リスナーをローカルで実行し、パブリック HTTPS トンネルを介してそのルートを公開し、その URL をサンドボックス アプリに登録して、PayPal の Webhook シミュレーターで実際のサンドボックス トランザクションまたは模擬イベントをトリガーします。 署名検証を有効にしておく: シミュレーター イベントとアプリ関連のサンドボックス イベントには重要なイベントがあります。検証の違いについては以下で説明します。
PayPal がローカルホストに直接送信できない理由
PayPal は、独自のサーバーから Webhook 通知を配信します。 http://localhost:3000/api/paypal などのアドレスは、PayPal の観点から見た PayPal のマシンを指しており、あなたのマシンではありません。 localhost トンネル は、アプリケーションをコンピュータ上に置いたまま、ローカル プロセスにパブリック HTTPS アドレスを与えます。
公式の PayPal Webhooks Simulator のドキュメント には、そのリスナーがポート 443 の HTTPS 経由で到達可能である必要があると記載されています。トンネルはそのパブリック TLS エンドポイントを処理し、リクエストを 3000 や 8080 などのローカル ポートに転送します。
適切な PayPal テスト パスを選択してください
リスナー開発用のシミュレーター イベントをモック
シミュレーターは、トランザクションを作成せずに、支払いのキャプチャ、返金、請求イベントなどの代表的なイベントを送信できます。これは、ルーティング、JSON 解析、応答コード、およびイベントのディスパッチを確認する最も速い方法です。モック イベントは REST アプリに関連付けられておらず、アプリの Webhook イベント ビューアーに表示されず、再送信できず、実際のトランザクションを表しません。
エンドツーエンドの動作のための実際のサンドボックス イベント
現実的な統合を行うには、PayPal 開発者ダッシュボードで REST アプリを作成し、トンネル エンドポイントを Webhook として追加し、必要なイベント タイプを選択して、サンドボックス チェックアウトまたは API 操作を完了します。これらのイベントはサンドボックス アプリに属し、運用前に使用するのと同じアプリ資格情報、Webhook ID、イベント ビューアー、および再送信ワークフローを実行します。
ローカルホストに PayPal Webhook を設定します
- アプリケーションを起動し、ルートがローカルで機能することを確認します:
curl -i -X POST http://localhost:3000/api/webhooks/paypal -H 'content-type: application/json' -d '{"event_type":"LOCAL.PING"}'. npx portpreview 3000を実行し、生成された HTTPS URL をコピーします。- 完全なコールバックを構築します (例:
https://your-subdomain.portpreview.dev/api/webhooks/paypal. )
- 模擬テストの場合は、Webhooks Simulator に貼り付けてイベントを選択します。アプリのテストの場合は、サンドボックス REST アプリの Webhook 設定の下に追加します。
- イベントを送信し、受信メソッド、PayPal ヘッダー、生の本文、ハンドラー ログ、および HTTP 応答を検査します。
アプリケーションが処理するイベントのみをサブスクライブします。幅広いサブスクリプションによりノイズが発生し、モデル化していないイベントのビジネス ロジックを誤って実行しやすくなります。
A practical Express listener
import express from 'express';
const app = express();
app.use(express.json({ verify: (req, _res, buf) => {
req.rawBody = Buffer.from(buf);
}}));
app.post('/api/webhooks/paypal', async (req, res) => {
const event = req.body;
// Verify first; do not fulfill an order from untrusted JSON.
const verified = await verifyPayPal(req.headers, event);
if (!verified) return res.status(401).send('invalid signature');
// Claim the event ID atomically so retries cannot duplicate work.
const firstDelivery = await claimEvent(event.id);
if (!firstDelivery) return res.sendStatus(200);
if (event.event_type === 'PAYMENT.CAPTURE.COMPLETED') {
await markOrderPaid(event.resource.id);
}
return res.sendStatus(200);
});
app.listen(3000);
確認応答作業は短くしてください。イベントを保存し、2xx 応答を返し、キュー内で遅い電子メールまたはフルフィルメント作業を実行します。イベント ID は自然冪等キーです。メモリ内のセットに依存するのではなく、一意のデータベース制約を強制します。
PayPal の署名を正しく検証してください
PayPal は、PAYPAL-AUTH-ALGO、PAYPAL-CERT-URL、PAYPAL-TRANSMISSION-ID、PAYPAL-TRANSMISSION-SIG、PAYPAL-TRANSMISSION-TIME などのヘッダーで送信メタデータを送信します。アプリ関連のイベントの場合、それらの値、Webhook ID、およびイベントをサンドボックス /v1/notifications/verify-webhook-signature API に送信できます。 HTTP 応答が成功するだけでは十分ではありません。 verification_status が SUCCESS と等しいことが必要です。 PayPal は、ローカル暗号化検証についても、webhook 統合ガイド.
シミュレーターに関する注意事項: PayPal のポストバック検証エンドポイントは、模擬シミュレーター イベントをサポートしていません。 PayPal は、シミュレーターの署名を自己検証するために、文字通りの Webhook ID WEBHOOK_ID を文書化します。この特別な値を、サンドボックス アプリに割り当てられた実際の Webhook ID と混同しないでください。当面の目標がポストバック API 自体をテストすることである場合は、模擬シミュレーター イベントの代わりに実際のサンドボックス トランザクションを生成します。
証明書をダウンロードする前に、証明書の URL が PayPal の文書化されたルールに従っていることを検証し、検証方法で必要な正確なイベント表現を保持し、アクセス トークン、クライアント シークレット、署名、または完全な支払いペイロードをログに記録しないでください。
お金を変えるイベントまたはアクセスするイベントをテストする
PAYMENT.CAPTURE.COMPLETED: 予想される注文識別子、金額、通貨、キャプチャ ステータスを確認した後にのみフルフィルメントを付与します。PAYMENT.CAPTURE.REFUNDED: 権利を安全に取り消し、部分的な払い戻しをサポートします。- チェックアウト注文イベント: 承認と完了したキャプチャを区別します。承認だけでは資金が確保されたことを証明するものではありません。
- サブスクリプション イベント: 請求ステート マシンに対するアクティブ化、一時停止、キャンセル、支払い失敗、および順序どおりでない配信のテスト。
プロバイダー イベントは通知であり、疑いの余地のないデータベース コマンドではありません。機密性の高い移行の場合は、認証された API 資格情報を使用して参照された PayPal リソースを取得し、それを自分の注文レコードと比較します。
失敗したローカル配信のトラブルシューティング
シミュレーターは接続できません
URL が https:// で始まり、正確な Webhook パスが含まれており、実行中のトンネルを指していることを確認します。 curl を使用してパブリック URL を自分でテストします。 404 は通常、パスまたはフレームワークのルートが間違っていることを意味します。 502 は通常、トンネルがローカル プロセスに到達できないことを意味します。
ハンドラーは 401
を返します最初に、イベントがシミュレーターから来たのか、それとも登録されたサンドボックス アプリから来たのかを判断します。 Webhook ID と検証方法を適宜確認してください。次に、プロキシがすべての PAYPAL-* ヘッダーを保持していること、およびライブ資格情報と api-m.sandbox.paypal.com.
PayPal が再試行するか、配信が失敗としてマークされます
イベントが永続的に受け入れられた後にのみ 2xx を返します。ルート上のリダイレクト、HTML エラー ページ、認証ミドルウェア、長時間の同期ジョブを避けてください。実際のアプリ イベントにはイベント ビューアを使用し、模擬配信診断にはシミュレーターの結果を使用します。永続的な処理パターンについては、再試行とべき等性ガイドを参照してください。
運用前のセキュリティ チェックリスト
- サンドボックスとライブ クライアントの認証情報、Webhook ID、およびエンドポイント シークレットを個別に使用します。
- ビジネス フィールドを解析したり状態を変更したりする前に、すべての署名を検証します。
- PayPal イベント ID によって重複を排除し、フルフィルメント トランザクションをアトミックにします。
POSTのみを許可し、リクエスト サイズを制限し、レート制限を適用し、可能な場合はトンネル URL を非公開にします。- ログから購入者のデータと認証情報を編集します。デバッグ中に公開されたものをすべて回転させます。
- 一時的なトンネル URL を安定した運用エンドポイントに置き換え、署名と再試行テストを繰り返します。
完全なイベントおよび検証スキーマについては、PayPal のプライマリ Webhook API リファレンス を使用してください。生の本体と安全な比較に関するフレームワークに依存しない詳細については、webhook 署名検証ガイド.
を参照してください。