Integrating a payment gateway is crucial for any modern web application offering payment functionalities. In this guide, you’ll learn how to integrate the PhonePe Payment Gateway into a Next.js application step-by-step. We’ll walk through creating a secure backend to process payments and a frontend form for user input, along with the complete code implementation.
Why Choose PhonePe?
PhonePe is one of India’s most popular payment platforms, offering a robust and secure payment gateway solution. Its features include:
- Ease of Integration: Comprehensive API documentation and SDK support.
- High Security: SHA-256 checksum validation.
- Multiple Payment Modes: Support for UPI, cards, net banking, and wallets.
Implementation Overview
The integration process involves two main steps:
- Backend Setup: Create an API to initiate payment requests and validate responses.
- Frontend Setup: Build a user-friendly interface for payment initiation.
Backend Setup
We’ll use a Next.js API Route
to handle PhonePe’s API communication.
Code for Payment Initiation API
import axios from "axios";
import crypto from "crypto";
import { NextResponse } from "next/server";
// Constants
let salt_key = "96434309-7796-489d-8924-ab56988a6076";
let merchant_id = "PGTESTPAYUAT86";
export async function POST(req) {
try {
let reqData = await req.json(); // Parse the request data
// Extract transaction details
let merchantTransactionId = reqData.transactionId;
// Prepare the payload
const data = {
merchantId: merchant_id,
merchantTransactionId: merchantTransactionId,
name: reqData.name,
amount: reqData.amount * 100, // Convert to paise (smallest currency unit)
redirectUrl: `http://localhost:3000/api/status?id=${merchantTransactionId}`,
redirectMode: "POST",
callbackUrl: `http://localhost:3000/api/status?id=${merchantTransactionId}`,
mobileNumber: reqData.mobile,
paymentInstrument: {
type: "PAY_PAGE",
},
};
// Encode payload as Base64
const payload = JSON.stringify(data);
const payloadMain = Buffer.from(payload).toString("base64");
// Generate checksum
const keyIndex = 1;
const string = payloadMain + "/pg/v1/pay" + salt_key;
const sha256 = crypto.createHash("sha256").update(string).digest("hex");
const checksum = `${sha256}###${keyIndex}`;
// Define PhonePe API URL
const prod_URL =
"https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/pay";
// API call options
const options = {
method: "POST",
url: prod_URL,
headers: {
accept: "application/json",
"Content-Type": "application/json",
"X-VERIFY": checksum,
},
data: {
request: payloadMain,
},
};
// Make the API call
const response = await axios(options);
// Return the response from PhonePe
return NextResponse.json(response.data);
} catch (error) {
console.error(error);
// Handle errors
return NextResponse.json(
{ error: "Payment initiation failed", details: error.message },
{ status: 500 }
);
}
}
Frontend Setup
Now, let’s build a user-friendly form where users can input their details and initiate the payment.
Code for Payment Form
"use client";
import { useState } from "react";
import axios from "axios";
export default function Home() {
const [name, setName] = useState("");
const [mobile, setMobile] = useState("");
const [amount, setAmount] = useState("");
const [loading, setLoading] = useState(false);
const handlePayment = async (e) => {
e.preventDefault();
setLoading(true);
// Prepare the data
const data = {
name: name,
amount: amount,
mobile,
transactionId: "T" + Date.now(),
};
try {
// Initiate payment
const response = await axios.post("http://localhost:3000/api/order", data);
// Redirect user to PhonePe payment page
if (
response.data &&
response.data.data.instrumentResponse.redirectInfo.url
) {
window.location.href =
response.data.data.instrumentResponse.redirectInfo.url;
}
} catch (err) {
console.error(err);
alert("Error initiating payment. Please try again.");
} finally {
setLoading(false);
}
};
return (
<div className="flex items-center justify-center h-screen bg-gradient-to-r from-indigo-50 to-green-500">
<div className="max-w-4xl p-8 bg-white rounded-lg shadow-md">
<h2 className="text-2xl font-bold text-center mb-4">
PhonePe Payment Gateway
</h2>
<form onSubmit={handlePayment} className="space-y-4">
<div>
<label>Name:</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full px-4 py-2 border rounded"
required
/>
</div>
<div>
<label>Mobile:</label>
<input
type="text"
value={mobile}
onChange={(e) => setMobile(e.target.value)}
className="w-full px-4 py-2 border rounded"
required
/>
</div>
<div>
<label>Amount:</label>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
className="w-full px-4 py-2 border rounded"
required
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full px-4 py-2 bg-blue-500 text-white rounded"
>
{loading ? "Processing..." : "Pay Now"}
</button>
</form>
</div>
</div>
);
}
How It Works
- Frontend Flow:
- Users fill in their details (name, mobile, amount).
- On form submission, the app sends a POST request to the backend API.
- Backend Flow:
- The backend generates a checksum to validate the payload.
- A payment request is sent to the PhonePe API.
- The PhonePe API responds with a redirection URL for the payment.
- Redirection:
- The user is redirected to PhonePe’s payment page to complete the transaction.
Testing
- Use PhonePe’s Sandbox API for testing.
- Ensure
merchant_id
andsalt_key
match the sandbox credentials. - Test with different amounts and inputs to validate the integration.
Key Learnings
- Checksum Validation: PhonePe uses SHA-256 checksum to ensure the security of API communication.
- Base64 Encoding: Payloads need to be encoded in Base64 before sending to the API.
- Redirects: Handle redirection URLs efficiently for better user experience.
Download Source Code
Integrating the PhonePe payment gateway in Next.js is straightforward with the right approach. With this setup, you can enable seamless payment functionality in your web application. Try this in your projects and let us know how it works for you! 🚀