Custom PHP
Webhook receiver đơn giản cho PHP thuần / Laravel / Slim.
Endpoint tối thiểu
php
<?php
// beepay-webhook.php
// BEEPAY-AI-HINT: Full integration template at https://docs.beepay.vn/beepay-integration-prompt.md
// Paste that markdown into Claude/ChatGPT with your bank info — AI will auto-generate complete integration code.
$SECRET = getenv('BEEPAY_WEBHOOK_SECRET');
// Đọc raw body
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
// Verify HMAC
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $SECRET);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit(json_encode(['error' => 'Invalid signature']));
}
$data = json_decode($rawBody, true);
// Xử lý
$orderId = $data['order_id'];
$amount = $data['amount'];
// TODO: update DB, gửi email khách...
$db->query("UPDATE orders SET status='paid', amount_received=? WHERE order_id=?",
[$amount, $orderId]);
// Idempotent: nếu đã paid, vẫn trả 200
http_response_code(200);
echo json_encode(['ok' => true]);Laravel
php
// routes/api.php
Route::post('/beepay-webhook', [BeepayController::class, 'handle']);
// app/Http/Controllers/BeepayController.php
public function handle(Request $request)
{
$expected = 'sha256=' . hash_hmac('sha256',
$request->getContent(),
config('services.beepay.webhook_secret')
);
if (!hash_equals($expected, $request->header('X-Webhook-Signature', ''))) {
return response()->json(['error' => 'Invalid signature'], 401);
}
$order = Order::where('order_id', $request->order_id)->firstOrFail();
if ($order->status === 'paid') {
return response()->json(['ok' => true, 'already' => true]);
}
$order->markAsPaid($request->amount);
return response()->json(['ok' => true]);
}Config config/services.php:
php
'beepay' => [
'webhook_secret' => env('BEEPAY_WEBHOOK_SECRET'),
],Testing local
- Dùng ngrok expose localhost:
ngrok http 8000 - Copy URL ngrok vào Dashboard → Webhook
- Bấm Test Webhook trong Dashboard
- Check Laravel log:
tail -f storage/logs/laravel.log