In online transactions, integrating payment gateways is a crucial step for any e-commerce platform. PhonePe, one of India’s leading digital payment platforms, offers businesses a robust payment gateway solution. In this comprehensive guide, we’ll integrate the PhonePe payment gateway into a React.js application.

Prerequisites:

  1. Basic understanding of React.js.
  2. Node.js and npm (Node Package Manager) installed on your machine.
  3. PhonePe Merchant Account (Sign up on the PhonePe Business platform).

Step 1: Setting Up the Server:

First, let’s set up the server to handle payment requests and callbacks.

  1. Create a new directory for your project and navigate into it.
  2. Initialize a new Node.js project by running npm init -y.
  3. Install required dependencies:
npm install express cors crypto axios body-parser dotenv
JavaScript

Create a .env file in the root directory and add your environment variables:

PORT=8000
SALT_KEY=your_salt_key
MERCHANT_ID=your_merchant_id
JavaScript

Write the server code by referring to the provided Node.js code snippet.

Step 2: Setting Up React App:

Now, let’s create a React.js application to interact with the server and initiate payments.

  1. Create a new React app using Create React App:
npx create-react-app phonepe-payment
JavaScript

Navigate into the newly created directory:

cd phonepe-payment
JavaScript

Install react-router-dom For navigation:

npm install react-router-dom
JavaScript

Create a new component named Payment to handle payment processing. Use the provided React component code snippet.

Step 3: Designing the Payment Form:

In the Payment Component: design a form to collect payment details such as name, mobile number, and amount. Also, include a button to trigger the payment process.

import React from 'react'
import axios from 'axios'
import { useNavigate } from 'react-router-dom'
const payment = () => {

    const navigate = useNavigate()

    const data = {
        name: 'Vikas',
        amount: 1,
        number: '9999999999',
        MUID: "MUID" + Date.now(),
        transactionId: 'T' + Date.now(),
    }

    const handlePayment = async (e) => {
        e.preventDefault();

        let res = await axios.post('http://localhost:8000/order', { ...data }).then(res => {

            console.log(res)
            if (res.data && res.data.data.instrumentResponse.redirectInfo.url) {
                window.location.href = res.data.data.instrumentResponse.redirectInfo.url;
            }
        })
            .catch(error => {
                console.error(error);
            });

    }


    return (
        <form onSubmit={handlePayment}>
            <div className='col-12 '>
                <p className='fs-5'><strong>Name:</strong> {data.name}</p>
            </div>
            <div className='col-12 '>
                <p className='fs-5'><strong>Number:</strong> {data.number}</p>
            </div>
            <div className='col-12 '>
                <p className='fs-5'><strong>Amount:</strong> {data.amount}Rs</p>
            </div>
            <div className='col-12 center'>
                <button className='w-100 ' type="submit">Pay Now</button>
            </div>

        </form>
    )
}

export default payment
JavaScript

Step 4: Handling Payment Request:

Implement the logic to send payment details to the server when the form is submitted. Upon receiving a response from the server, redirect the user to the PhonePe payment page.

const express = require("express");
const cors = require("cors");
const crypto = require("crypto");
const axios = require("axios");
const bodyParser = require("body-parser");



require("dotenv").config();


const app = express();
app.use(express.json());
app.use(express.urlencoded({
    extended: false
}));
app.use(cors());
app.use(bodyParser.urlencoded({
    extended: false
}));



let salt_key = process.env.SALT_KEY
let merchant_id = process.env.MERCHANT_ID

app.get("/", (req, res) => {
    res.send("server is running");
})


app.post("/order", async (req, res) => {

    try {
        console.log(req.body)

        const merchantTransactionId = req.body.transactionId;
        const data = {
            merchantId: merchant_id,
            merchantTransactionId: merchantTransactionId,
            merchantUserId: req.body.MUID,
            name: req.body.name,
            amount: req.body.amount * 100,
            redirectUrl: `http://localhost:8000/status/?id=${merchantTransactionId}`,
            redirectMode: 'POST',
            mobileNumber: req.body.number,
            paymentInstrument: {
                type: 'PAY_PAGE'
            }
        };
        const payload = JSON.stringify(data);
        const payloadMain = Buffer.from(payload).toString('base64');
        const keyIndex = 1;
        const string = payloadMain + '/pg/v1/pay' + salt_key;
        const sha256 = crypto.createHash('sha256').update(string).digest('hex');
        const checksum = sha256 + '###' + keyIndex;

        // const prod_URL = "https://api.phonepe.com/apis/hermes/pg/v1/pay"
        const prod_URL = "https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/pay"

        const options = {
            method: 'POST',
            url: prod_URL,
            headers: {
                accept: 'application/json',
                'Content-Type': 'application/json',
                'X-VERIFY': checksum
            },
            data: {
                request: payloadMain
            }
        };

        axios.request(options).then(function (response) {
                console.log(response.data)

                return res.json(response.data)
            })
            .catch(function (error) {
                console.error(error);
            });

    } catch (error) {
        res.status(500).send({
            message: error.message,
            success: false
        })
    }

})


app.post("/status", async (req, res) => {

    const merchantTransactionId = req.query.id
    const merchantId = merchant_id

    const keyIndex = 1;
    const string = `/pg/v1/status/${merchantId}/${merchantTransactionId}` + salt_key;
    const sha256 = crypto.createHash('sha256').update(string).digest('hex');
    const checksum = sha256 + "###" + keyIndex;

    const options = {
        method: 'GET',
        url: `https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/status/${merchantId}/${merchantTransactionId}`,
        headers: {
            accept: 'application/json',
            'Content-Type': 'application/json',
            'X-VERIFY': checksum,
            'X-MERCHANT-ID': `${merchantId}`
        }
    };

    // CHECK PAYMENT TATUS
    axios.request(options).then(async (response) => {
            if (response.data.success === true) {
                const url = `http://localhost:5173/success`
                return res.redirect(url)
            } else {
                const url = `http://localhost:5173/failure`
                return res.redirect(url)
            }
        })
        .catch((error) => {
            console.error(error);
        });

})


app.listen(process.env.PORT, () => {
    console.log(`Server is running on port ${process.env.PORT}`);
})
JavaScript

Step 5: Handling Payment Callbacks:

Create routes on the server to handle payment status callbacks from PhonePe. Verify the payment status and redirect the user to success or failure pages accordingly.

Step 6: Testing:

Test the payment flow by making a payment through the React app. Verify if the payment is processed successfully and if the callback mechanism works as expected.

Download Source Code

Conclusion

Integrating the PhonePe payment gateway into a React.js application involves setting up a server to handle payment requests and callbacks, designing a payment form in React, and implementing the logic to initiate payments and handle payment status callbacks. By following this comprehensive guide, you can seamlessly integrate PhonePe’s robust payment solution into your React.js application, enabling smooth and secure online transactions for your users.