Razorpay Integration Guide: 5 Mistakes That Break Payments
Source: Dev.to
Many developers can open the checkout page, but still run into issues such as:
- ❌ Payments not verifying
- ❌ Incorrect amounts being charged
- ❌ Successful payments not recorded
- ❌ Order status not updating
After fixing multiple Razorpay integrations, I noticed something interesting:
Most payment failures happen because of a few small mistakes.
In this guide you’ll learn the 5 most common Razorpay integration mistakes — and how to avoid them.
📚 Table of Contents
- Razorpay Payment Flow
- Mistake #1: Creating Orders on the Frontend
- Mistake #2: Using the Wrong Amount Format
- Mistake #3: Skipping Payment Verification
- Mistake #4: Not Implementing Webhooks
- Mistake #5: Using Test Keys in Production
- Final Thoughts
Razorpay Payment Flow (Overview)
Before looking at the mistakes, it’s important to understand the correct payment flow.
flowchart TD
A[User clicks Pay] --> B[Frontend sends request to Backend]
B --> C[Backend creates order using Razorpay API]
C --> D[Order ID returned to Frontend]
D --> E[Frontend opens Razorpay Checkout]
E --> F[User completes payment]
F --> G[Frontend sends payment details to Backend]
G --> H[Backend verifies payment signature]
H --> I[Payment confirmed]
Key Principles
- ✔ Orders should be created on the backend.
- ✔ Checkout runs on the frontend.
- ✔ Payment verification must happen on the backend.
This separation ensures security and reliability.
❌ Mistake #1: Creating Orders on the Frontend
A very common mistake is trying to create Razorpay orders directly from the frontend.
❌ Wrong Approach
// frontend (DO NOT DO THIS)
fetch("https://api.razorpay.com/v1/orders")
This exposes your secret API key, which is extremely dangerous. Anyone could inspect the code and misuse it.
✅ Correct Approach
Orders should always be created on the backend.
// backend (Node.js example)
const Razorpay = require("razorpay");
const razorpay = new Razorpay({
key_id: process.env.RAZORPAY_KEY_ID,
key_secret: process.env.RAZORPAY_KEY_SECRET,
});
const order = await razorpay.orders.create({
amount: 50000, // amount in paise
currency: "INR",
receipt: "receipt_123",
});
Secure Order Creation Flow
flowchart TD
A[User clicks Pay] --> B[Frontend requests backend to create order]
B --> C[Backend calls Razorpay API]
C --> D[Razorpay returns Order ID]
D --> E[Backend sends Order ID to frontend]
E --> F[Checkout opens]
❌ Mistake #2: Using the Wrong Amount Format
Razorpay expects the amount in paise, not rupees. This tiny detail causes many integrations to fail.
❌ Incorrect Example
amount: 500 // ❌ This is 500 INR, but Razorpay expects paise
✅ Correct Example
amount: 500 * 100 // ✅ 500 INR → 50000 paise
If the customer needs to pay ₹500, Razorpay expects:
50000 // 500 × 100
Amount Conversion Flow
flowchart TD
A[Customer payment: 500 INR] --> B[Convert to paise]
B --> C[500 × 100]
C --> D[Send 50000 to Razorpay]
Rule to remember
Amount sent to Razorpay = Rupees × 100
❌ Mistake #3: Skipping Payment Verification
Many developers assume that if Razorpay Checkout shows “Payment Successful”, the payment is complete. That is not enough proof.
You must verify the payment signature on your backend.
Payment Verification Flow
flowchart TD
A[User completes payment] --> B[Razorpay sends payment response to frontend]
B --> C[Frontend sends payment_id, order_id, signature to backend]
C --> D[Backend verifies signature using Razorpay secret key]
D --> E[Backend confirms payment]
Without verification, attackers could fake payment responses.
❌ Mistake #4: Not Implementing Webhooks
Relying only on the frontend response works during testing, but in production payments can be:
- delayed
- retried
- refunded
- partially captured
Webhooks notify your backend when these events happen.
Webhook Event Flow
flowchart TD
A[Payment event occurs on Razorpay] --> B[Razorpay sends webhook request]
B --> C[Your backend webhook endpoint receives event]
C --> D[Backend updates database]
D --> E[Order status updated]
Common webhook events include:
payment.captured
payment.failed
refund.processed
Without webhooks, your backend won’t know the real payment state.
❌ Mistake #5: Using Test Keys in Production
This mistake happens more often than you think. During development Razorpay provides test API keys. If those keys are deployed to production, real payments will fail.
Environment Variables
RAZORPAY_KEY_ID=
RAZORPAY_KEY_SECRET=
Deployment Flow
flowchart TD
A[Development] --> B[Use Razorpay Test Keys]
B --> C[Testing completed]
C --> D[Switch to Live Keys]
D --> E[Deploy to Production]
Always double‑check the keys before deployment.
Final Thoughts
Payment integrations rarely fail because of complex code. They fail because of small details developers overlook, such as:
- Creating orders on the wrong layer
- Sending incorrect amounts
- Skipping payment verification
- Ignoring webhooks
- Deploying with test credentials
By following the patterns outlined above, you can build a secure, reliable Razorpay integration that works flawlessly in production. Happy coding!
## Common Razorpay Integration Mistakes
- Ignoring webhooks
- Deploying with test keys
Fixing these five mistakes will make your Razorpay integration:
- ✅ Secure
- ✅ Reliable
- ✅ Production‑ready
### 💬 Discussion
Have you faced issues integrating Razorpay in production?
What was the **hardest part of the payment integration**?
Share your experience in the comments 👇