An easy way to integrate PhonePe payment gateway into the Node.js backend and React-front-end respectively to allow secure UPI-based transactions in your web application.

Key Points

  • As of 2024, 50+ Crore Registered Users on PhonePe across India.
  • With over 48% Market Share in UPI transactions, it remains the most used UPI platform in India.
  • More than 7.5 Billion Transactions are processed every month through PhonePe in the early months of 2024.
Digittrix Blog Author Image

Co-Founder

Harsh Abrol Digittrix Blog Author Image

3 min read

With Over 14 years of Experience in the IT Field, Helping Companies Optimise there Products for more Conversions

image showing phonepe icon with react and node js icon to show integration

Introduction

PhonePe is one of the primary digital payment platforms in India, which is widely used for making seamless transactions on eCommerce platforms, mobile application development, and web project development. When integrated into a Node.js and React-based application, PhonePe ensures secure and efficient payment options for the users.

This guide illustrates step-by-step approaches to integrate PhonePe into your application built on Node.js and React.js. This integration shall assist you in fast-tracking the transaction process whether you are working on eCommerce, a service-based platform, or a mobile application development project. 

Why Integrate PhonePe in Your Application?

  • Secure Transactions: PhonePe uses encryption levels and security standards such as those adopted by the industry.

  • Fast Processing: The processing of transactions takes place in real-time with very little delay.

  • Wide Acceptance: PhonePe is used to pay by more than 400 million users across India.

  • Multi-Platform: The PhonePe integration works perfectly on web and mobile applications.

  • Seamless User Experience: Less friction at the checkout improves conversions.

Prerequisites

Before integrating PhonePe, ensure you have:

  • A PhonePe Business account.

  • Access to the PhonePe Developer Portal.

  • A merchant ID and salt key (provided by PhonePe).

  • A Node.js environment (Node.js v14+ recommended).

  • A React.js application for frontend integration.

  • Basic knowledge of REST APIs and Express.js for backend setup

Setting Up Your Node.js Backend for PhonePe Integration

Step 1: Initialize a Node.js Project

Run the following commands in your terminal to create a new project:

mkdir phonepe-integration && cd phonepe-integration

npm init -y

Step 2: Install Required Dependencies

npm init -y

npm install express axios crypto dotenv uuid

Step 3: Create Environment Variables

Create a .env file to store sensitive data.

                                        # Environment variables for PhonePe Payment Gateway

PORT=8000
PHONEPE_MERCHANT_ID=TESTMERCHANTUAT
PHONEPE_SALT_KEY=bb7d9e93-0759-49e1-a6b3-4b664668d076
PHONEPE_SALT_INDEX=1
PROJECT_URL=http://localhost:8000/payment-status
PROJECT_STATUS_URL=http://localhost:8000/payment-status
PROJECT_SUCCESS_URL=http://localhost:8000/status/success
PROJECT_FAILURE_URL=http://localhost:8000/status/failed
PHONEPE_API_URL=https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/pay     # For production, use https://api.phonepe.com/apis/hermes/pg/v1/pay
PHONEPE_STATUS_URL=https://api
                                        
                                    

API Endpoints for Payment Processing

Initialize Payment

  • Endpoint: POST /initialize-payment
  • Description: Initiates a PhonePe payment and returns a redirect URL to complete the transaction.
  • Request Body:

                                        {
  "phone": "9999999999",
  "amount": 100
}
                                        
                                    

  • Response

                                        {
  "success": true,
  "message": "Payment initiated",
  "redirectUrl": "https://mercury-uat.phonepe.com/pay"
}
                                        
                                    

  • Redirect the user to the redirectUrl to complete payment.

Verify Payment Status

Endpoint: POST /verify-status?transactionId=YOUR_TRANSACTION_ID
Description: Verifies the transaction status and redirects accordingly.

  • Request Parameters

transactionId - Unique identifier for the transaction

  • Response:

If success, redirects to: http://localhost:5173/success

If failed, redirects to: http://localhost:5173/failed

Code Implementation

Create server.js and add the following code:

                                        import express from "express";
import dotenv from "dotenv";
import crypto from "crypto";
import { v4 as uuidv4 } from "uuid";
import axios from "axios";
import cors from "cors";

dotenv.config();

const app = express();
const port = process.env.PORT || 8080;

// Load environment variables
const {
 PHONEPE_MERCHANT_ID,
 PHONEPE_SALT_KEY,
 PHONEPE_SALT_INDEX,
 REDIRECT_URL,
 FRONTEND_SUCCESS_URL,
 FRONTEND_FAILURE_URL,
 PHONEPE_BASE_URL,
 PHONEPE_STATUS_URL,
} = process.env;

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Root Route
app.get("/", (req, res) => {
 res.send("PhonePe Payment Gateway API is running.");
});

/**
* Function to generate a checksum (SHA256 hash)
*/
const generateChecksum = (payload, endpoint) => {
 const stringToHash = payload + endpoint + PHONEPE_SALT_KEY;
 const sha256 = crypto.createHash("sha256").update(stringToHash).digest("hex");
 return `${sha256}###${PHONEPE_SALT_INDEX}`;
};

/**
* Initialize Payment API
* Endpoint: POST /initialize-payment
*/
app.post("/initialize-payment", async (req, res) => {
 try {
   const { phone, amount } = req.body;
   if (!phone || !amount) {
     return res
       .status(400)
       .json({ success: false, message: "Invalid request parameters" });
   }

   const transactionId = uuidv4();

   const paymentPayload = {
     merchantId: PHONEPE_MERCHANT_ID,
     merchantUserId: "1",
     mobileNumber: phone,
     amount: Number(amount) * 100, // Convert to paisa
     merchantTransactionId: transactionId,
     redirectUrl: `${REDIRECT_URL}?transactionId=${transactionId}`,
     redirectMode: "POST",
     paymentInstrument: { type: "PAY_PAGE" },
   };

   const payload = Buffer.from(JSON.stringify(paymentPayload)).toString(
     "base64"
   );
   const checksum = generateChecksum(payload, "/pg/v1/pay");

   const response = await axios.post(
     PHONEPE_BASE_URL,
     { request: payload },
     {
       headers: {
         "Content-Type": "application/json",
         "X-VERIFY": checksum,
         "X-MERCHANT-ID": PHONEPE_MERCHANT_ID,
       },
     }
   );

   return res.status(200).json({
     success: true,
     message: "Payment initiated",
     redirectUrl: response.data.data.instrumentResponse.redirectInfo.url,
   });
 } catch (error) {
   console.error("Payment Initialization Error:", error);
   return res.status(500).json({
     success: false,
     message: "Payment initialization failed",
     error: error.message,
   });
 }
});

/**
* Verify Payment Status API
* Endpoint: POST /verify-status
*/
app.post("/verify-status", async (req, res) => {
 try {
   const { transactionId } = req.query;
   if (!transactionId) {
     return res
       .status(400)
       .json({ success: false, message: "Transaction ID is required" });
   }

   const statusUrl = `${PHONEPE_STATUS_URL}/${PHONEPE_MERCHANT_ID}/${transactionId}`;
   const checksum = generateChecksum(
     "",
     `/pg/v1/status/${PHONEPE_MERCHANT_ID}/${transactionId}`
   );

   const response = await axios.get(statusUrl, {
     headers: {
       "Content-Type": "application/json",
       "X-VERIFY": checksum,
     },
   });

   const paymentStatus = response.data.success
     ? FRONTEND_SUCCESS_URL
     : FRONTEND_FAILURE_URL;
   return res.redirect(paymentStatus);
 } catch (error) {
   console.error("Payment Status Verification Error:", error);
   return res.redirect(FRONTEND_FAILURE_URL);
 }
});

// Start the server
app.listen(port, () => {
 console.log(`Server running on port ${port}`);
});
                                        
                                    

Deployment Considerations

  • Use HTTPS – Secure communication for payment processing
  • Store API keys securely – Use .env 
  • Change Urls– Change sandbox phonepe url and frontend url with live url
  • Ensure that it's Mobile & Web Compatible- Tested across multiple devices and browsers.

Final Words

Integrating PhonePe into your Node.js and React.js application guarantees a secure, seamless, and user-friendly payment experience. This integration shall benefit developers involved in mobile app development, web development, and payment app development, enabling them to manage transactions efficiently through PhonePe.

Do you want help implementing this?

Get a summary via Google for

$0

Get Help Now!

Tech Stack & Version

 Backend

  • Node.js: v20.x

  • Express.js: v4.18.x

  • Dotenv: v16.x

Frontend

  • React: v18.x

  • Axios: v1.6.x

 Deployment

  • Vercel

  • Netlify

  • AWS EC2
img

©2025Digittrix Infotech Private Limited , All rights reserved.