前回の記事では、PAY.JPの決済機能を導入する方法を解説しました。
今回は、Webhookを使った決済通知方法について説明していきます。
Laravel11から一部書き方が変更されているため、この記事ではLaravel10とLaravel11の違いや、
変更後の書き方についても解説していきます。
パッケージのインストール手順は先ほど説明した内容の「決済機能の導入方法はこちらへ」から
確認してください。
Webhookとは?
Webhookとは、あるサービスで何かイベント(できごと)が起きたときに、指定されたURL(あなたのサーバー)に対して自動的に通知(HTTPリクエスト)を送る仕組みです。
ざっくり言うと、外部サービスからの自動連絡ですね。。。!
これをすることで、ユーザーが画面を開いていなくても、バックグラウンドでイベントに反応できたり
外部サービスとのリアルタイムな連携ができるんです!
PAY.JPの「秘密鍵(APIキー)」を.envに設定
秘密鍵はPAY.JPの管理画面にあるので、PAY.JPに接続してください。

発行元トークンからwhook_**************************をCOPYしてください。
COPYしたKeyを.envに記載します。
.env
PAYJP_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxx #テスト用の秘密鍵
PAYJP_WEBHOOK_SECRET=whook_xxxxxxxxxxxxxxxxx #ここに追加
Webhookを受け入れるURLを作成
Laravel側で「POSTリクエストを受け付けるURL」を作成する必要があるので
PAY.JP管理ページからURLを作成します。
設定ページは添付画像を参照してください。

添付画像で赤の枠で目印しているボタンをクリックすると
モーダルが表示されるので、入力欄にURLを入力してください。
下の添付画像を参考に設定してください。

今はテストモードとします。実際に稼働している場合はテストモードにしてくださいね。
ライブモードにしないと動きませんので。。。
CSRFトークンの除外
LaravelでWebhookを受け取るには、CSRFトークンのチェックをスキップする必要があります。
Laravel 11では、これまで使われていた VerifyCsrfToken ミドルウェアの $except プロパティは使われなくなり、
設定方法が変更されています。
以下のように新しい書き方で除外ルートを指定しましょう。
設定ファイルの編集: bootstrap/app.php
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'webhook', // ここに追加
]);
})
->create();
Laravel10の場合
Laravel 10では、app/Http/Middleware/VerifyCsrfToken.phpファイルでCSRFトークンの除外ルートを指定します。
このファイルを開き、$exceptプロパティにWebhookのURI(/webhook)を追加します。
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
*/
protected $except = [
'webhook', // ここに追加
];
}
ドメイン部分は含めないので注意!!!
Webhook用のルートを作成する
Laravel 11ではルート定義ファイルが routes/web.php の他に routes/api.php に分かれています。
Webhookは基本的に api.php でOKです。
以下コードを参考にしてください。
use App\Http\Controllers\PayjpWebhookController;//追加
Route::post('/webhook', [PayjpWebhookController::class, 'webhook']);
WebhookControllerを作成する
ターミナルでControllerを作成します。以下のコマンドを実行してください。
WebhookControllerとしてますが、名前はなんでも良いです。好みで。
php artisan make:controller WebhookController
次にPAY.JPから送られてくるリクエストデータを処理していきます。
ここでは、決済完了などのイベント通知に含まれるデータを受け取り、必要な情報を取得していく流れを解説します。
app/Http/Controllers/WebhookController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class WebhookController extends Controller
{
public function webhook(Request $request)
{
$payload = $request->getContent();
$event = json_decode($payload, true);
// イベントの種類によって処理を分ける
if ($event['object'] === 'event') {
switch ($event['type']) {
case 'charge.succeeded':
// 決済成功時の処理
//データベースに保存、決済メールの送信など。。
break;
case 'charge.failed':
// 決済の失敗時の処理
break;
// 他のイベントも必要に応じて追加
}
}
return response()->json(['status' => 'ok']);
}
}
決済成功のタイミングで、自動的にメール通知を送ることも可能です。
$event = json_decode($payload, true);
取得したJSON文字列は、json_decode を使ってPHPの連想配列に変換し、そこから必要な情報を取り出します。
決済金額をデータベースで管理したい場合も、Webhookから送られてくるJSONデータから金額を取得できます。
たとえば、customer IDを取得したい場合は以下のようにします。
$event['data']['customer'] → "cus_xxxx"
このように、用途に応じて必要なデータを取り出して処理していきましょう!!
ただし、customer IDが誰のものかを特定できるように、PAY.JP側や自社のデータベースで正しく紐づけて管理しておくことが重要です。
以上がPAY.JPのWebhookで決済を通知する方法です。
Webhookを活用すれば、決済完了後に自動でメールを送信したり、データベースに記録したりと、様々な処理を自動化できます。
PAY.JPはテストモードで自由に試すことができるので、クレジット決済の仕組みに興味がある方は、ぜひ一度触ってみてください!