Step-by-Step Guide: Implementing PhonePe Payment Gateway in PHP

This comprehensive guide walks you through the process of integrating the PhonePe Payment Gateway into your PHP website. Beginning with the creation of an HTML form to collect user information and payment details, the tutorial ensures a seamless user experience. The backend PHP code for form submission handles the generation of a unique transaction ID, constructs the payload for PhonePe, and initiates the payment process. Each step is accompanied by detailed comments to facilitate understanding.

The guide also covers the crucial aspect of callback handling using the callback.php file. This file ensures that your system receives and processes the status of the payment transaction, allowing you to update your database accordingly. The code includes error handling and verification steps to ensure the integrity of the payment process.

With the provided code and comments, even those with limited experience in PHP can successfully implement PhonePe Payment Gateway into their web applications. Whether you’re developing a small business website or a more complex application, this guide provides the necessary foundation to seamlessly integrate PhonePe payments, enhancing the overall functionality and user experience of your PHP website.

HTML Form

Create a simple HTML form to collect user information and payment details. Save it as index.php:

1<form method="POST" action="submit-appointment.php">
2    <!-- User Name -->
3    <label for="name">Name:</label>
4    <input type="text" id="name" name="name" required>
5
6    <!-- User Email -->
7    <label for="email">Email:</label>
8    <input type="email" id="email" name="email" required>
9
10    <!-- User Phone -->
11    <label for="phone">Phone:</label>
12    <input type="tel" id="phone" name="phone" pattern="[0-9]{10}" required>
13
14    <!-- Amount -->
15    <label for="amount">Amount:</label>
16    <input type="number" id="amount" name="amount" required>
17
18    <!-- Submit Button -->
19    <button type="submit">Submit</button>
20</form>

2. Backend Code to Handle Form Submission

Create submit-appointment.php to handle form submission and initiate PhonePe payment:

1<?php
2// Import your connection
3require('connection.php');
4
5if (isset($_POST['name'], $_POST['email'], $_POST['phone'], $_POST['amount'])) {
6    // Create a unique transaction ID
7    $transactionId = date('dmYhmi') . rand(111111, 999999);
8    $amount = $_POST['amount'];
9    $phone = $_POST['phone'];
10
11    // Construct the payload for PhonePe
12    $eventPayload = [
13        'merchantId' => 'PGTESTPAYUAT',
14        'merchantTransactionId' => $transactionId,
15        'merchantUserId' => 'MUID123',
16        'amount' => $amount,
17        'redirectUrl' => 'YOUR_ENDPOINT/callback.php',
18        'redirectMode' => 'POST',
19        'callbackUrl' => 'YOUR_ENDPOINT/callback.php',
20        'mobileNumber' => $phone,
21        'paymentInstrument' => [
22            'type' => 'PAY_PAGE',
23        ],
24    ];
25
26    // Encode payload to base64
27    $encodedPayload = base64_encode(json_encode($eventPayload));
28
29    // Set API Key and Index
30    $saltKey = '099eb0cd-02cf-4e2a-8aca-3e6c6aff0399'; // Your API Key
31    $saltIndex = 1;
32
33    // Construct X-VERIFY header
34    $string = $encodedPayload . '/pg/v1/pay' . $saltKey;
35    $sha256 = hash('sha256', $string);
36    $finalXHeader = $sha256 . '###' . $saltIndex;
37
38    // Set headers for the request
39    $headers = [
40        'Content-Type: application/json',
41        'X-VERIFY: ' . $finalXHeader,
42    ];
43
44    // Define PhonePe API URL
45    $phonePayUrl = 'https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/pay'; // For Development
46    // $phonePayUrl = 'https://api.phonepe.com/apis/hermes/pg/v1/pay'; // For Production
47
48    // Prepare data for the request
49    $data = [
50        'request' => $encodedPayload,
51    ];
52
53    // Set options for the HTTP request
54    $options = [
55        'http' => [
56            'method' => 'POST',
57            'content' => json_encode($data),
58            'header' => implode("\r\n", $headers),
59        ],
60    ];
61
62    // Create a stream context
63    $context = stream_context_create($options);
64
65    // Make the request to PhonePe API
66    $response = file_get_contents($phonePayUrl, false, $context);
67
68    // Decode the response
69    $result = json_decode($response, true);
70
71    // Extract the redirect URL for payment
72    $redirectUrl = $result['data']['instrumentResponse']['redirectInfo']['url'];
73
74    // Redirect the user to PhonePe for payment
75    header("Location: $redirectUrl");
76    exit();
77} else {
78    // Handle invalid form submission
79    echo "400 Bad Request";
80}
81?>

3. Callback Handling

Create callback.php to handle the callback from PhonePe after the payment is processed:

Using CURL:

1<?php
2// Define PhonePe gateway information
3$gateway = (object) [
4    'token' => 'PGTESTPAYUAT',
5    'secret_key' => '099eb0cd-02cf-4e2a-8aca-3e6c6aff0399',
6];
7
8// Extract transaction ID from POST data
9$orderId = $_POST['transactionId'];
10
11// Construct X-VERIFY header for status check
12$encodeIn265 = hash('sha256', '/pg/v1/status/' . $gateway->token . '/' . $orderId . $gateway->secret_key) . '###1';
13
14// Set headers for the status check request
15$headers = [
16    'Content-Type: application/json',
17    'X-MERCHANT-ID: ' . $gateway->token,
18    'X-VERIFY: ' . $encodeIn265,
19    'Accept: application/json',
20];
21
22// Define PhonePe status check URL
23$phonePeStatusUrl = 'https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/status/' . $gateway->token . '/' . $orderId; // For Development
24// $phonePeStatusUrl = 'https://api.phonepe.com/apis/hermes/pg/v1/status/' . $gateway->token . '/' . $orderId; // For Production
25
26// Initialize cURL for status check
27$ch = curl_init();
28curl_setopt($ch, CURLOPT_URL, $phonePeStatusUrl);
29curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
30curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
31$response = curl_exec($ch);
32curl_close($ch);
33
34// Decode the status check response
35$api_response = json_decode($response);
36
37// Check if the payment was successful
38if ($api_response->code == "PAYMENT_SUCCESS") {
39    // Insert payment details into your database
40    $insert = mysqli_query($conn, "INSERT INTO YOUR_TABLE SET payment_txn_id = '{$api_response->data->merchantTransactionId}', payment_amount = '{$api_response->data->amount}' WHERE id = 'YOUR_REF_ID'");
41    echo "Thank you for your payment. We will contact you shortly!";
42} else {
43    // Handle failed transactions
44    echo "Transaction Failed";
45}
46?>