INSTANT NOTIFICATIONS

Webhook Callback Documentation

Webhooks allow your server to receive real-time HTTP POST notifications as soon as an incoming UPI transaction is matched and verified by Qolor Pay.

1. How Webhooks Work

Understand the automated event lifecycle when a customer makes a payment:

  1. A customer scans the Dynamic QR code and completes payment via any UPI app (GPay, PhonePe, Paytm, etc.).
  2. Qolor Pay validates the incoming UPI UTR reference number in real-time.
  3. Our backend triggers an HTTP POST request sending payment data directly to your saved Webhook URL.
  4. Your endpoint verifies the data, updates the order status in your database, and replies with an HTTP 200 OK response.

2. Webhook Payload Structure

Qolor Pay delivers the following 4 parameters in the POST payload body:

Field Name Type Description
status String Payment status confirmation (e.g. SUCCESS, COMPLETED).
order_id String The unique Order ID passed during your initial order creation request.
amount Numeric The exact amount paid by the customer in INR.
utr String The 12-digit Unique Transaction Reference (UTR) generated by the bank/UPI network.
EXAMPLE POST PAYLOAD (JSON / Form Data) application/json or application/x-www-form-urlencoded
{
  "status": "SUCCESS",
  "order_id": "ORD_982348234",
  "amount": "399.00",
  "utr": "423456789012"
}

3. Demo Receiver Script (PHP)

Use this complete implementation file as a blueprint for your webhook.php receiver:

webhook.php PHP Implementation
<?php
// Set headers for standard JSON response
header('Content-Type: application/json');

// 1. Capture incoming payload (Supports both JSON and POST form data)
$raw_input = file_get_contents('php://input');
$data = json_decode($raw_input, true);

if (!$data) {
    $data = $_POST;
}

// 2. Extract the four key fields
$status   = isset($data['status']) ? trim($data['status']) : '';
$order_id = isset($data['order_id']) ? trim($data['order_id']) : '';
$amount   = isset($data['amount']) ? trim($data['amount']) : '';
$utr      = isset($data['utr']) ? trim($data['utr']) : '';

// 3. Basic validation
if (empty($status) || empty($order_id) || empty($amount) || empty($utr)) {
    http_response_code(400);
    echo json_encode(["status" => false, "message" => "Missing required webhook parameters."]);
    exit();
}

// 4. Verify payment status
if ($status === 'SUCCESS' || $status === 'COMPLETED') {
    
    /*
     * DATABASE LOGIC HERE:
     * 1. Query your database to find the order by $order_id
     * 2. Verify that the order is still in 'PENDING' status (prevents double fulfillment)
     * 3. Verify that the received $amount matches the expected order amount
     * 4. Update the order status to 'SUCCESS', save the $utr number, and credit the user/service
     *
     * Example:
     * $stmt = $db->prepare("UPDATE orders SET status='PAID', utr=? WHERE order_id=? AND amount=?");
     * $stmt->execute([$utr, $order_id, $amount]);
     */

    // 5. Always respond with 200 OK to acknowledge receipt
    http_response_code(200);
    echo json_encode(["status" => true, "message" => "Webhook processed successfully."]);
    exit();

} else {
    // Handle failed or cancelled transactions
    http_response_code(200);
    echo json_encode(["status" => false, "message" => "Transaction marked unfulfilled."]);
    exit();
}
?>
Security Best Practice: Always check whether an order has already been marked as PAID before granting user credits or shipping items to protect against duplicate webhook events.