先日、PAY.JPの定期課金において、定期課金時に送信されるWebhookの挙動や決済に失敗した場合の再開方法などを説明しました。
PAY.JPの定期課金(サブスクリプション)におけるWebhookの挙動と決済再開について
前回の記事ではどういうWebhookが送られてくるかについて書きましたが、今回の記事では実際に送られてくるWebhookのデータ(Json)がどのようなデータ構造なのか、公式ドキュメントでは確認しにくかったため、PAY.JPのダッシュボードを使いながら、まとめて行きたいと思います。
Webhookのデータ構造について
定期課金(サブスクリプション)のサービスを開発する場合、サービス側とPAY.JP側で同期をとるためにはWebhookの情報は不可欠です。
公式ドキュメントには、Webhookの詳細な説明はありますが、Webhookで送られてくるデータについては決済が成功した場合のみで、イベントの種類ごとには書かれていません。
イベントの一覧は APIリファレンス – イベントとWebhook をご参照ください。
以下は、5000円の支払いが成功したときに Webhook で送信されるイベントのデータ例です。
{ "created": 1442212986, "data": { "amount": 5000, "amount_refunded": 0, "captured": true, "captured_at": 1442212986, "card": { "address_city": null, "address_line1": null, "address_line2": null, "address_state": null, "address_zip": null, "address_zip_check": "unchecked", "brand": "Visa", "country": null, "created": 1442212986, "customer": null, "cvc_check": "passed", "exp_month": 1, "exp_year": 2016, "fingerprint": "e1d8225886e3a7211127df751c86787f", "id": "car_f0984a6f68a730b7e1814ceabfe1", "last4": "4242", "name": null, "object": "card" }, "created": 1442212986, "currency": "jpy", "customer": null, "description": null, "expired_at": null, "failure_code": null, "failure_message": null, "id": "ch_bcb7776459913c743c20e9f9351d4", "livemode": false, "object": "charge", "paid": true, "refund_reason": null, "refunded": false, "subscription": null }, "id": "evnt_5328acdbdb5294d6fc9cc903f8c", "livemode": false, "object": "event", "pending_webhooks": 1, "type": "charge.succeeded" }Webhook | PAY.JP:イベント
dataにはイベントの詳細内容が入ります。API で返ってくるレスポンスと同様の JSON データです。pending_webhooksでは、まだ Webhook が正常に受信されていない送信先 URL の数を示しています。
この決済成功の最後の「”type”: “charge.succeeded”」の部分が、イベントの種類によって変わってくるわけですが、失敗した場合のデータの内容って当然異なります。
これについては、基本的にAPIで試験をした際に返ってくるレスポンスを参考にして下さい、という感じだったのですが、それでも心配だったので、どうにか確認出来ないかと思ったところ、PAY.JP上でWebhookの試験データを送る方法がありました。
Webhookデータを確認する方法(ngrokを使う方法)
Webhookのデータ内容、構造を確認するだけであればPAY.JPダッシュボードから対象のURLにWebhook試験を送信して、そのデータを確認すればOKです。
そのWebhookの受取先としてngrokを使います。
ngrokはローカル開発環境を一時的に専用URLを発行し、外からでもアクセス出来るようにするツールです。
既にご利用の方は読み飛ばしていただいてOKです。
アカウントの作成

まずはアカウントが必要なので、アカウントを作成しましょう。

アカウント作成が終わると、Welcome画面になると思うので、OSに応じてngrokのインストールを行います。
ngrokの起動
無事ngrokがインストールできたら、テキストエディタで、以下のコマンドを実行するとURLが発行されます。
ngrok http 8000
このコマンドを実行すると以下のようにURLが表示されます。
Call internal services from your gateway: https://ngrok.com/r/http-request ession Status online Version 3.24.0-msix Region Japan (jp) Web Interface http://127.0.0.1:4040 Forwarding https://testtest.ngrok-free.app -> http://localhost:8000
このなかで、Forwardingが外部に公開されたURLになるので、Webhookの送信先のURLに設定します。(testtestは例として入れた物です)
そして、Web InterfaceのURLがngrokが受け取ったデータが表示されるURLとなります。
どちらも画面を見ながらやってみます。
実際にWebhookをngrokに送信してみる
それではPAY.JPダッシュボードでWebhookの送信先を設定して、送信までやってみましょう。

『API設定』を開いて少し下にスクロールすると、Webhookという項目があるので、その中の『Webhookを追加』ボタンをクリックします。

URLに先程Forwardingで表示された、https://testtest.ngrok-free.appと、Webhookを受け取る(POSTが受け取れる)パスを入れておきます。
テストモードを選択して、登録をクリックします。
これで準備はOKです。

テストイベントを送信をクリック。

URLは先程登録したURLを選択。
イベントの種類は何でも良いのですが、charge.succeededはもう分かっているので、決済失敗のcharge.failedを選択して、登録をクリックします。
すると、恐らくHTTPステータスは500などが表示されるかと思います。
これは、Webhookを受け取った後に、一般的な作りとしてSubscription IDを参照して処理が始まると思うのですが、このWebhookはダミーデータを送っているだけなので、受け取ったデータのユーザーが存在せずNULLになって、処理できずサーバーエラーになっているからですね。
なので、このエラーは気にせず、送られてきたデータを確認してみましょう。
送られてきたデータを確認するためには、コンソールに表示されていたngrokのWeb Interface (http://127.0.0.1:4040)にアクセスしてみます。

そうするとこのような画面が表示されます。
POST /api/webhooks/payjp 500 Internal Server Errorの箇所をクリックすると、右側に送信されてきたJSONデータが表示されているのが分かります。
これが決済失敗のときに送られてくるWebhookデータということになります。
このように、ngrokを利用すると各イベントのデータ構造が分かります。
ですので、Webhookで受け取る予定のデータについては、このやり方で試験データとして控えておくと良いかなと思います。
実際の試験はGitbashから手動で送るしかない
では、実際にローカル開発環境やサーバー上でWebhook試験をする場合はどうするかというと、これはしようがありませんが、手動でPOSTするしかありません。
私の場合は、Gitbashを使って、以下の雛形を使って疑似的に手動でWebhook試験をしています。
curl -X POST http://127.0.0.1:8000/api/webhooks/payjp \
-H "Content-Type: application/json" \
-d '{
"object": "event",
"livemode": false,
"id": "evnt_xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"data": {
"object": "subscription",
"livemode": false,
"metadata": {},
"id": "sub_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"canceled_at": null,
"current_period_end": 1767245427,
"current_period_start": 1764567027,
"paused_at": 1764567027,
"resumed_at": null,
"customer": "cus_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"plan": {
"object": "plan",
"livemode": false,
"metadata": {},
"id": "pln_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"name": null,
"amount": 0,
"currency": "jpy",
"interval": null,
"billing_day": null,
"trial_days": 0,
"created": 1764567027
},
"next_cycle_plan": null,
"start": null,
"status": "paused",
"trial_start": null,
"trial_end": null,
"prorate": null,
"created": 1764567027
},
"pending_webhooks": 0,
"created": 1764567027,
"type": "subscription.paused"
}
このデータの中で、sub_、cus_、pln_で始まるものについては、実際にPAY.JPで作成されたデータを使わないと当然先程のような500エラーになってしまうので、試験時にはここを都度書き換える必要があります。
私はPHPでLaravelで開発しているので、Dusk試験という自動試験を行うのですが、データベースからデータをもってきてJSONの構造にしてあとは、送信するだけというように、、、出来れば良いのですが、今はわざわざPAY.JP上のデータをもってきて貼り付けてやっています。。。
まとめ
今回は、PAY.JPのWebhookのデータ構造についてngrokを使って確認する方法をまとめてみました。
こうして送られてくる実際のデータが分かると、安心して作成出来ますね。
Webhookの試験については、どうしても完全自動化までできないのがちょっとした悩みですが、この記事がお役に立てれば嬉しいです。
以上、PAY.JPのWebhookで送信される各イベントのデータ構造(JSON)をngrokを使って確認する方法でした。
TEDASKはPAY.JPの決済導入を承っております。なるべく短期間でリリースできるようにご支援しておりますので、お気軽にお問い合わせください。



コメント