This guide explains how to integrate the Razorpay payment gateway using the unified-pay-core package. It covers setup, configuration, and key operations like creating payments, capturing payments, processing refunds, and handling webhooks.
Prerequisites
- Node.js and npm installed.
- A Razorpay account with API keys (Key ID and Key Secret).
- A webhook secret for verifying webhook events.
- Install the unified-pay-core package:
npm install unified-pay-core
Setup
Obtain Razorpay Credentials
- Log in to your Razorpay Dashboard.
- Get your Key ID (
rzp_test_...
) and Key Secret for test or live mode. - Set up a webhook in the Razorpay Dashboard and obtain the Webhook Secret.
Install Dependencies
Ensure you have express and cors for the example server:
npm install express cors
Configure the Gateway
Initialize the Razorpay gateway using the createGateways
function.
const express = require("express");
const cors = require("cors");
const { createGateways } = require("unified-pay-core");
const app = express();
app.use(cors());
app.use("/webhook/razorpay", express.raw({ type: "application/json" }));
app.use(express.json());
const { razorpay } = createGateways([
{
gateway: "razorpay",
config: {
apiKey:process.env.API_KEY,
apiSecret: process.env.API_SECRET,
webhookSecret: "your_webhook_secret",
},
},
]);
Key Operations
1. Create a Payment
Create a payment order to initiate a transaction.
app.post("/create-payment", async (req, res) => {
try {
const { amount, currency = "INR", metadata } = req.body;
if (!amount) {
return res.status(400).json({ error: "Amount is required" });
}
const payment = await razorpay.processPayment(amount, currency, metadata || {});
res.json({
success: true,
orderId: payment.transactionId,
transactionId: payment.transactionId,
metadata: payment.metadata,
});
} catch (error) {
console.error("Razorpay payment creation error:", error);
res.status(500).json({ success: false, error: "Payment creation failed" });
}
});
Input:
amount
: Payment amount (e.g., 20 for ₹20.00).currency
: Currency code (e.g., "INR").metadata
: Optional key-value pairs for additional data.
Output:
orderId
: Razorpay Order ID (order_...
) for client-side payment processing.
💡 Developer Note: After calling
processPayment
, use the returnedorderId
(which is a Razorpay Order ID starting withorder_
) to initiate payment on the frontend using Razorpay's client SDK. Pass thisorderId
as theorder_id
parameter in the Razorpay checkout options. The customer will then complete the payment, and you'll receive a Payment ID (pay_...
) in the success handler for subsequent operations like capture, refund, and verification.
2. Capture a Payment
Capture a payment after the customer completes the payment process.
app.post("/capture-payment", async (req, res) => {
try {
const { paymentId } = req.body;
if (!paymentId || !paymentId.startsWith("pay_")) {
return res.status(400).json({ error: "Valid paymentId is required" });
}
const capture = await razorpay.capturePayment(paymentId);
const verification = await razorpay.verifyPayment(paymentId);
res.status(capture.success ? 200 : 400).json({ capture, verification });
} catch (error) {
console.error("Payment capture error:", error);
res.status(500).json({ error: "Payment capture failed" });
}
});
Input:
paymentId
: The Payment ID (pay_...
) from the Razorpay payment process.
Output:
capture
: Payment response with status, amount, and currency.verification
: Verification details confirming the payment status.
3. Process a Refund
Refund a captured payment (full or partial).
app.post("/refund-payment", async (req, res) => {
try {
const { paymentId, amount } = req.body;
if (!paymentId || !paymentId.startsWith("pay_")) {
return res.status(400).json({ error: "Valid paymentId is required" });
}
const refund = await razorpay.processRefund(
paymentId,
amount ? parseFloat(amount) : undefined
);
res.json({
success: refund.success,
refundId: refund.refundId,
transactionId: paymentId,
status: refund.status,
amount: refund.amount,
currency: refund.currency,
});
} catch (error) {
console.error("Refund Error:", error);
res.status(500).json({ success: false, error: "Refund failed" });
}
});
Input:
paymentId
: The Payment ID (pay_...
) to refund.amount
: Optional partial refund amount (e.g., 10 for ₹10.00).
Output:
refundId
: Razorpay Refund ID (rfnd_...
).status
: Refund status (succeeded, pending, failed).
4. Verify a Payment
Verify the status of a payment.
const verification = await razorpay.verifyPayment(paymentId);
Input:
paymentId
: The Payment ID to verify.
Output:
verified
: Boolean indicating if the verification was successful.status
: Payment status (succeeded, pending, failed).isValid
: Boolean indicating if the payment is valid (e.g., captured).
5. Handle Webhooks
Set up a webhook endpoint to receive and process Razorpay events.
app.post("/webhook/razorpay", async (req, res) => {
try {
const rawBodyString = req.body.toString();
const result = await razorpay.handleWebhookEvent(rawBodyString, req.headers);
if (result === "INVALID") {
return res.status(400).send("Invalid webhook signature");
}
const parsedBody = JSON.parse(rawBodyString);
const eventType = parsedBody.event;
switch (eventType) {
case "payment.captured":
console.log("Payment captured:", parsedBody.payload.payment.entity.id);
break;
case "payment.failed":
console.log("Payment failed:", parsedBody.payload.payment.entity.id);
break;
case "order.paid":
console.log("Order paid:", parsedBody.payload.order.entity.id);
break;
case "refund.processed":
console.log("Refund processed:", parsedBody.payload.refund.entity.id);
break;
default:
console.log("Unhandled event:", eventType);
}
res.status(200).send("OK");
} catch (error) {
console.error("Webhook processing error:", error);
res.status(500).send("Webhook processing failed");
}
});
Setup:
- Use
express.raw({ type: "application/json" })
for the webhook route. - Configure the webhook URL in the Razorpay Dashboard (e.g.,
https://yourdomain.com/webhook/razorpay
).
Supported Events:
payment.captured
payment.failed
order.paid
refund.processed
Webhook Testing
- Use ngrok to expose your local server:
ngrok http 3000
. - Update the webhook URL in the Razorpay Dashboard.
- Test events like
payment.captured
ororder.paid
using Razorpay's webhook testing tools.
Payment Flow Summary
Here's the complete payment flow for better understanding:
- Backend: Call
processPayment()
→ Returns Order ID (order_...
) - Frontend: Use Order ID with Razorpay checkout SDK → Customer completes payment → Returns Payment ID (
pay_...
) - Backend: Use Payment ID for
capturePayment()
,processRefund()
,verifyPayment()
Notes
- Order vs. Payment ID:
processPayment
returns an Order ID (order_...
). After customer payment, use the Payment ID (pay_...
) for capture, refund, and verification. - Amount Handling: Razorpay expects amounts in paise (e.g., ₹20.00 = 2000).
- Webhook Secret: Ensure
webhookSecret
is set for signature verification. - Error Handling: Check
success
anderror
fields in responses to handle failures. - Client-Side Integration: Use the Order ID with Razorpay's checkout script to collect payment details.