When integrating Razorpay with a MERN stack application (MongoDB, Express, React, Node.js), one issue appears again and again for developers:
Payment succeeds on Razorpay, but backend verification fails.
The payment popup shows “Payment Successful”, but your server rejects the request or does not store the payment in the database. This can break order confirmation, subscriptions, or digital product delivery.
In this article, we’ll focus on one specific problem — Razorpay payment signature verification failure — and show exactly how to fix it.
The Problem: Razorpay Payment Verification Failed
After a user completes payment, Razorpay sends three important values to your frontend:
razorpay_payment_idrazorpay_order_idrazorpay_signature
Your backend must verify these values to confirm that the payment is authentic and not tampered with.
However, many MERN developers get an error like:
Payment verification failed
Invalid signature
Even though the payment was successful.
Why This Happens
The most common reason is incorrect signature generation on the backend.
Razorpay expects you to generate a hash using:
order_id + "|" + payment_id
and then compare it with the razorpay_signature.
If even one small detail is wrong, verification fails.
Common mistakes include:
- Using wrong environment variable for secret key
- Wrong string format
- Using payment_id before order_id
- Missing
|separator - Not using SHA256 hashing
Correct Razorpay Payment Verification (Node.js)
Here is the correct way to verify Razorpay payments in a MERN backend.
const crypto = require("crypto");
app.post("/verify-payment", (req, res) => {
const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body;
const body = razorpay_order_id + "|" + razorpay_payment_id;
const expectedSignature = crypto
.createHmac("sha256", process.env.RAZORPAY_SECRET)
.update(body.toString())
.digest("hex");
if (expectedSignature === razorpay_signature) {
res.json({
success: true,
message: "Payment verified successfully"
});
} else {
res.status(400).json({
success: false,
message: "Payment verification failed"
});
}
});
If implemented correctly, this will solve 90% of Razorpay verification issues in MERN apps.
Important Things Most Developers Miss
1️⃣ Never Verify Payment on the Frontend
Verification must always happen on the Node.js backend, because your Razorpay secret key should never be exposed in React.
2️⃣ Use Environment Variables
Your secret key should always be stored like this:
RAZORPAY_KEY_ID=xxxxxxxx
RAZORPAY_SECRET=xxxxxxxx
And accessed with:
process.env.RAZORPAY_SECRET
3️⃣ Make Sure Order is Created from Backend
Always create Razorpay orders using your Express server, not directly from React.
This prevents manipulation of the payment amount.
Correct MERN Razorpay Payment Flow
A secure flow looks like this:
- React user clicks Pay Now
- React calls backend
/create-order - Node.js creates Razorpay order
- React opens Razorpay checkout
- User completes payment
- Backend
/verify-paymentchecks signature - Store payment data in MongoDB
If verification fails, you simply reject the order.
Final Thoughts
The Razorpay signature verification error is one of the most common issues developers face when integrating payments in a MERN stack application.
The good news is that the fix is simple once you understand how Razorpay generates signatures.
Always verify payments on the backend, generate the hash correctly, and keep your secret keys secure.
Once implemented properly, Razorpay becomes a very reliable payment solution for MERN applications.
Open for Freelance Work
If you need help with:
- MERN Stack Development
- Razorpay or Stripe Integration
- Payment Gateway Debugging
- Backend API Development
- Startup MVP Development
DM me Fiverr — I’m open for freelance work and collaborations.
Top comments (0)