You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Paystack支付网关的Webhook实现:解决用户支付成功未跳转回调URL的补单问题

Fixing Paystack Post-Payment Benefit Distribution with Webhooks

Hey there, I see the issue you're facing—users completing payments but not getting their benefits because they don't hit the callback URL. Webhooks are exactly the safety net you need here, since Paystack will send a direct notification to your server regardless of whether the user redirects after payment. Let's walk through how to set this up properly.

Step 1: Configure Your Paystack Webhook Endpoint

First, head over to your Paystack dashboard:

  • Go to Settings > Webhooks
  • Add your webhook endpoint URL (e.g., https://your-domain.com/webhook.php—note this needs to be publicly accessible; for local testing, use tools like ngrok to expose your localhost)
  • Save your secret key (you'll use this later to verify incoming requests are actually from Paystack)

Step 2: Write the Webhook Handler Script (webhook.php)

This script will listen for Paystack's event notifications, validate them, and trigger your benefit distribution logic. The key here is signature verification (to block fake requests) and idempotency (to avoid giving users benefits twice).

Here's a complete, production-ready example:

<?php
// Retrieve raw POST data from Paystack
$input = file_get_contents('php://input');
$event = json_decode($input);

// Your Paystack secret key (match the one in your initialize/callback scripts)
$secretKey = 'sk_test_2563a843c7ddd24e92450fe2ce91f3f18a57ad27';

// Verify the request is legitimate using Paystack's signature
$signature = isset($_SERVER['HTTP_X_PAYSTACK_SIGNATURE']) ? $_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] : '';
$hash = hash_hmac('sha512', $input, $secretKey);

if ($hash !== $signature) {
    // Invalid signature—reject the request
    http_response_code(403);
    die('Invalid request signature');
}

// Only process successful transaction events
if ($event->event === 'transaction.success') {
    $tranxData = $event->data;
    $reference = $tranxData->reference;
    
    // First, check if this transaction was already processed (idempotency check)
    // Replace with your actual database connection and query
    $pdo = new PDO('mysql:host=localhost;dbname=your_store_db', 'db_user', 'db_pass');
    $stmt = $pdo->prepare("SELECT id FROM orders WHERE payment_reference = ?");
    $stmt->execute([$reference]);
    $existingOrder = $stmt->fetch(PDO::FETCH_ASSOC);
    
    if ($existingOrder) {
        // Order already handled—do nothing to avoid duplicates
        http_response_code(200);
        die('Order already processed');
    }
    
    // Run your benefit distribution logic
    processSuccessfulPayment($tranxData);
    
    // Confirm receipt to Paystack
    http_response_code(200);
    echo 'Webhook processed successfully';
} else {
    // Ignore non-success events (like failed transactions)
    http_response_code(200);
    die('Unsupported event type');
}

// Reusable function to handle successful payments (copy your callback logic here)
function processSuccessfulPayment($tranxData) {
    // 1. Insert order and payment details into your database
    // Use $tranxData->reference, $tranxData->amount, $tranxData->customer->email, etc.
    
    // 2. Grant user benefits (e.g., unlock digital products, add subscription access)
    
    // 3. Send confirmation email to the user
    
    // 4. Clear the user's cart or unset session data
    // For guest users, link the transaction to their email/order details
}
?>

Step 3: Refactor Your Existing Callback Script

To avoid duplicate code, update your order.php callback to use the same processSuccessfulPayment function. This ensures both the callback and webhook use identical logic:

<?php
$curl = curl_init();
$reference = isset($_GET['reference']) ? $_GET['reference'] : '';
if(!$reference){
    die('No reference supplied');
}

curl_setopt_array($curl, array(
    CURLOPT_URL => "https://api.paystack.co/transaction/verify/" . rawurlencode($reference),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "accept: application/json",
        "authorization: Bearer sk_test_2563a843c7ddd24e92450fe2ce91f3f18a57ad27",
        "cache-control: no-cache"
    ],
));

$response = curl_exec($curl);
$err = curl_error($curl);

if($err){
    die('Curl returned error: ' . $err);
}
$tranx = json_decode($response);

if(!$tranx->status){
    die('API returned error: ' . $tranx->message);
}

if('success' == $tranx->data->status){
    // Check if webhook already processed this order
    $pdo = new PDO('mysql:host=localhost;dbname=your_store_db', 'db_user', 'db_pass');
    $stmt = $pdo->prepare("SELECT id FROM orders WHERE payment_reference = ?");
    $stmt->execute([$reference]);
    $existingOrder = $stmt->fetch(PDO::FETCH_ASSOC);
    
    if (!$existingOrder) {
        // Use the same reusable function as the webhook
        processSuccessfulPayment($tranx->data);
    }
}

// Include the reusable function (or require it from a separate file for cleaner code)
function processSuccessfulPayment($tranxData) {
    // Same logic as in webhook.php
}
?>

Key Best Practices

  • Never Skip Signature Verification: Malicious actors could send fake payment events to your webhook—this step blocks them.
  • Idempotency is Critical: Always check if the transaction was already processed before running your logic. This prevents duplicate benefits if both the callback and webhook trigger (which can happen occasionally).
  • Public Accessibility: Your webhook URL must be reachable by Paystack's servers. Localhost won't work unless you use a tunneling tool like ngrok for testing.
  • Add Logging: Write webhook events to a log file (e.g., file_put_contents('webhook_logs.txt', $input . PHP_EOL, FILE_APPEND);) to debug issues if something goes wrong.

Testing the Webhook

  • Use Paystack's test mode to simulate a successful payment.
  • Close the payment page immediately after paying (to avoid hitting the callback URL) and check your database to confirm benefits are granted.
  • Verify that duplicate events don't result in duplicate orders or benefits.

内容的提问来源于stack exchange,提问作者Browyn Louis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 05:14:08