How I Prevented Duplicate Orders, Payment Race Conditions & Inventory Corruption in a Production Ecommerce System
A deep dive into idempotency, payment verification, inventory consistency, race conditions, and duplicate order prevention in production ecommerce systems.
By Uttam Thapa · · Backend
🔄 Introduction
Building an ecommerce platform is not just about displaying products and collecting payments. One of the biggest challenges is ensuring that every payment results in exactly one valid order while maintaining accurate inventory and preventing data corruption.
📌 What This Guide Covers: Duplicate order prevention, payment race conditions, inventory protection, idempotent processing, and production reliability strategies.
While developing Velvet Loop and Golden Leaf Knots, I encountered several scenarios involving duplicate payment verification, inventory inconsistencies, abandoned sessions, and race conditions. Solving these issues became critical before deploying the platforms to production.
This article explains how I prevented duplicate orders, handled payment race conditions, protected inventory, and built a more reliable ecommerce system.
⚠️ Why Duplicate Orders Are Dangerous
📦
Inventory Loss
- • Stock deducted multiple times
- • Products appear out of stock
- • Inventory records inaccurate
😕
Customer Confusion
- • Multiple order confirmations
- • Duplicate order IDs
- • Incorrect purchase history
📊
Revenue Issues
- • Inflated revenue numbers
- • Incorrect conversion metrics
- • Misleading analytics
🏢
Admin Challenges
- • Duplicate shipments
- • Refund complications
- • Manual investigation overhead
For ecommerce businesses, duplicate orders directly affect customer trust and operational efficiency.
🔍 How I Discovered The Problem
The issue was discovered during Razorpay payment testing. While inspecting payment verification flows, I noticed that the verification endpoint could potentially be called multiple times for a single payment.
⚡ Key Discovery: The payment itself was legitimate, but repeated verification requests created the possibility of generating duplicate orders. Database testing confirmed that this scenario required additional safeguards before production deployment.
📋 Duplicate Order Scenario #1: Repeated Verification
💰 Customer Pays
↓
📨 Verification Request Sent
↓
📝 Order Created
↓
🔄 Verification Triggered Again
↓
⚠️ Potential Second Order
🚨 Root Cause: The payment was valid, but verification requests were not protected against multiple executions. Without additional validation, every successful verification could potentially create another order.
📋 Duplicate Order Scenario #2: Real-World Retry Situations
🔄 Browser Refresh
Payment Success → Customer Refreshes Page → Verification Triggered Again
🌐 Network Retry
Slow Network → Request Timeout → Automatic Retry → Duplicate Verification
🐛 Frontend Bugs
Verification Function → Accidentally Executes Twice → Duplicate Processing
😕 User Confusion
Customer Thinks Payment Failed → Attempts Again → Additional Requests
These scenarios highlighted the need for idempotent payment processing.
⚠️ Payment Verification Challenges
✅ Payment Success, Order Missing
Possible if: Database failure, server crash, or transaction interruption.
🔐 Order Created Before Verification
This was intentionally avoided by architecture design. Orders are never created before successful payment verification.
🔄 Duplicate Verification
The most common risk. Solved using payment identity validation.
🔒 Invalid Signatures
Protected using Razorpay HMAC SHA256 verification.
📊 Session Management Challenges
🚪 Abandoned Payments
Checkout Started → Payment Modal Opened → Customer Leaves
Result: Session remains incomplete, no order created.
❌ Failed Payments
Session status becomes FAILED.
⏰ Expired Sessions
Returning users require fresh validation before continuing checkout.
🔑 Invalid Session IDs
Any tampered session identifiers are rejected immediately.
📦 Inventory Protection
Inventory consistency was one of the most important requirements. Initially, duplicate orders could potentially reduce stock multiple times.
⚠️
Potential Risks
- Duplicate stock deductions
- Negative inventory
- Overselling products
✅
Final Solution
Inventory updates occur only after: payment verification ✓ order validation ✓ database transaction execution ✓
🏁 Race Conditions
Race conditions occur when multiple customers attempt to purchase limited inventory simultaneously.
📦 Available Stock = 1
👤 Customer A Pays 👤 Customer B Pays
↓
Both Attempt Checkout Simultaneously
⚠️ Without Safeguards
- Two successful orders created
- Inventory becomes negative
✅ Mitigation Strategy
- Stock Validation before payment
- Final Inventory Check in transaction
- Prisma Transactions for atomicity
🗄️ Database Protection Layers
🔍 Existing Order Validation
Find Order By razorpayPaymentId
If an order already exists, the system returns the existing record instead of creating another one.
✅ Payment Session Validation
Session Exists
Session Valid
Session Not Failed
🔒 Database Transactions
Prisma transactions guarantee: Inventory Update + Order Creation + Session Completion either all succeed together or all fail together.
🔄 Implementing Idempotency
One of the most important improvements was introducing idempotent payment processing.
Goal: One Payment = One Order
regardless of how many times verification executes
🔑 Identifier Used: razorpayPaymentId
📨 Verification Request
↓
🔍 Find Order By Payment ID
↓
❓ Exists?
↓ YES → 📋 Return Existing Order
↓ NO → 📝 Create New Order
This guarantees that each payment produces only one order.
🔐 Final Duplicate Protection Logic
1. Receive Verification Request
2. Verify Razorpay Signature
3. Find Existing Order by Payment ID
4. If Order Exists → Return Existing Order
5. Validate Session
6. Validate Inventory
7. Execute Database Transaction
8. Reduce Stock
9. Create Order
10. Complete Session
11. Send Emails
12. Return Success
✅ This architecture completely prevents duplicate order creation.
🐛 The Hardest Bug
🚨
Problem: Duplicate Orders
Symptoms: One payment, potentially multiple orders.
Cause: Verification endpoint lacked idempotency.
Time Invested: Multiple debugging sessions, numerous payment tests, database investigations, architecture reviews.
✅
Final Solution
Use razorpayPaymentId as the unique payment identity and validate its existence before creating new orders.
One Payment = One Order
⚠️ Error Handling Strategy
Verification Failure → Session marked FAILED, no order created
Network Failure → Idempotent processing prevents duplicates
Database Failure → Transaction rollback executed
Inventory Failure → Transaction aborted, no partial updates
Email Failure → Order remains successful, email retries later
📧 Important Design Decision: Customer orders are never blocked because of notification failures.
🚀 Deployment Challenges
🖥️ Render
- Cold starts affecting response times
- Health monitoring with
/health endpoint
🗄️ Database
- Connection management
- Transaction reliability in production
🔐 Environment Variables
- Razorpay credentials
- Database URLs, SMTP credentials
📧 Email Infrastructure
- Resend restrictions → migrated to Gmail SMTP
📚 Lessons Learned
🔒 Never trust frontend payment success
🔄 Payment verification must be idempotent
📦 Inventory updates belong after verification
🗄️ Database transactions are mandatory
📧 Email systems should never block order creation
🐛 Production systems fail in unexpected ways
⚠️ Edge cases matter more than happy paths
"The most important lesson was that payment systems are fundamentally data consistency systems. Collecting money is easy. Maintaining integrity across orders, inventory, payments, and notifications is the real challenge."
🔮 Future Improvements
Razorpay Webhooks
Payment Audit Logs
Monitoring & Alerts
Retry Queues
Inventory Reservation System
Event-Driven Order Processing
Advanced Analytics Dashboard
Fraud Detection Systems
🎯 Conclusion
🛡️
Preventing duplicate orders requires much more than a payment gateway integration. It requires careful architecture design, transaction management, inventory protection, session tracking, and idempotent processing.
✅ The final system implemented in Velvet Loop and Golden Leaf Knots ensures that every successful payment creates exactly one order while maintaining accurate inventory and reliable business operations.
Frequently asked questions
What causes duplicate orders in an ecommerce system?
Usually an impatient double click, a retried network request, or a webhook delivered more than once. All three send the same intent twice, and without an idempotency key the server treats them as two separate purchases.
How does an idempotency key prevent duplicate charges?
The client generates a unique key per checkout attempt and sends it with the request. The server stores it against the resulting order, so a repeat of the same key returns the original order instead of creating a second one. It turns retrying into a safe operation.
Are database transactions enough to prevent race conditions?
Not on their own. A transaction guarantees all-or-nothing, but two concurrent transactions can still both read the same stock level before either writes. You need a conditional update or an appropriate lock so one of them fails cleanly.
Home · Projects · Blog · Services · Résumé · Contact