E-commerce system design: handling flash sales, inventory and payment failures

Reserve stock before payment, treat timeouts as unknown, and reconcile webhooks against orders, so a payment ends in an order or a clean refund.

Read time
20 min
Word count
3.2K
Sections
13
FAQs
8
Share
Laptop showing an online store with a Buy Now button, linked to traffic, inventory, payment, order and refund cards
On this page · 13 sections
  1. Why flash sales are hard to operate
  2. What happens when 150 customers click Buy Now for 100 units?
  3. A reference architecture for a high-traffic checkout
  4. When payment succeeds but the order is cancelled
  5. Why a payment can succeed when an order cannot be confirmed
  6. Should the platform collect payment before confirming stock?
  7. How to recover from a partial failure
  8. What this means for reported sales
  9. How to measure checkout reliability
  10. What to test before a major sale
  11. A successful payment is not a successful order
  12. How eCorpIT can help
  13. References

Summary. A flash sale tests whether stock, checkout, payment and order systems stay correct under pressure, not only whether the site stays up. If 150 customers click Buy Now for 100 units, the platform must allocate each unit once and must not charge for stock it cannot supply. The safer design reserves stock with a concurrency-safe operation before payment starts, treats a timeout as an unknown result rather than a failure, trusts server-side payment status over the browser, and reconciles orders, stock and payments until each transaction reaches a known final state. Late payments are a real case: Razorpay says fewer than 0.5% of its payments are authorised late, and on 100,000 payments even 0.5% would be 500 orders. The scale is public. Flipkart reported 6.3 million concurrent users in a minute during the opening hour of Big Billion Days 2026, and Amazon India reported more than 18,000 orders per minute at the Prime Day 2025 peak. Neither company publishes its full checkout design, so what follows is a reference architecture, not a description of their systems.

About this article. This is for engineering leads and product owners preparing an online store or marketplace for a large sale. We checked company figures against Flipkart, Amazon and AWS publications, and the technical guidance against Shopify Engineering, Razorpay, MySQL and AWS documentation, on 3 November 2026. Flipkart and Amazon do not publish their production checkout architecture, so we make no claim about the databases, brokers or payment sequences they use. The 100-unit example and the refund arithmetic are our own illustrations, not reported incidents. Nothing here is accounting advice, and payment behaviour depends on your provider contract. Researched with AI assistance and reviewed by our editorial team.

Why flash sales are hard to operate

A flash sale creates a sharp rise in demand over a short period. Customers refresh product pages, compare prices, add to cart, apply offers and attempt checkout at almost the same moment.

The platforms' own figures show the scale:

  • Flipkart reported 6.3 million concurrent users in a minute during the opening hour of Big Billion Days 2026, and more than 287 million sessions from early access.
  • Flipkart's Chief Product and Technology Officer said in October 2023 that the platform handled 1.5 million requests per second when the sale opened. That is a 2023 figure, not a statement of current capacity.
  • Amazon India reported that Prime Day 2025 orders peaked at more than 18,000 per minute. Its Prime Day 2026 results page gives no equivalent figure.

These numbers measure different things. Concurrent users, requests per second, sessions and orders per minute cannot be compared or converted into one another. They do show why a sale needs more preparation than extra web servers.

A product page can take a very large number of views without most visitors trying to buy. Checkout is a different job: it must decide correctly on price, stock, payment and fulfilment for every order attempt.

What happens when 150 customers click Buy Now for 100 units?

Take this example:

Item Value
Sellable stock 100 units
Customers attempting to buy 150
Quantity per customer 1 unit
Maximum successful reservations 100

The platform must never give one unit to two customers, and that gets harder when requests arrive milliseconds apart.

The race condition

Suppose many requests read the stock value at nearly the same time. If the check and the deduction are separate operations, several requests can read the same value before any of them updates it:

  1. Customer A reads that one unit is available.
  1. Customer B reads that one unit is available before A's update commits.
  1. Both requests continue as though the product is available.
  1. Without protection, the application allocates the same final unit twice.

This is a race condition: the result depends on the timing of concurrent operations.

A stock message on a product page is not a reservation. It may come from cached or recently synchronised data. The authoritative decision belongs in checkout, against the records used to allocate stock.

Make the stock change atomic

The usual starting point is a conditional, atomic deduction. For a one-unit example:


            UPDATE inventory
SET available_to_sell = available_to_sell - 1
WHERE sku = 'PHONE-001'
  AND available_to_sell > 0;
          

The application then checks how many rows changed:

  • One row updated: the request secured one unit, subject to the surrounding reservation transaction.
  • Zero rows updated: nothing was available, so checkout must not continue as though stock was secured.

This stops overselling, but it does not solve throughput. Every buyer of a popular item queues on the same row. Shopify says its earlier MySQL attempts failed for that reason: a single row with a quantity column could not handle the contention.

What Shopify did about contention

Shopify's May 2026 engineering post describes moving reservations from Redis to MySQL. It now keeps one row per sellable unit, and uses SKIP LOCKED so that a transaction takes other free rows instead of waiting on rows that are already locked. MySQL's manual confirms that a locking read with this option never waits for a row lock and leaves locked rows out of the result.

To keep the table small, Shopify holds a bounded pool of at most 1,000 rows per item and location, refilled from the inventory ledger. Keeping reservations and the ledger in one database also gave it transactions across both steps, which removed failures such as a payment succeeding while stock is not claimed.

This is Shopify's design, not evidence of how Flipkart or Amazon work. A production service must also handle warehouses, seller ownership, damaged stock, safety stock, reservation expiry and cancellation.

A reference architecture for a high-traffic checkout

This is a generic design for an e-commerce platform. It is not a diagram of any company's private systems.


            Customers
  -> CDN and edge protection
  -> API gateway and load balancer
       -> Product and search services
       -> Cart and checkout orchestrator
            -> Pricing and promotion validation
            -> Inventory reservation service
            -> Order management service
            -> Payment gateway
                 -> Verified payment status (webhook)
                      -> Order management service

Order management service
  -> Order and inventory reconciliation
  -> Event or message queue
       -> Warehouse and fulfilment -> Delivery and tracking
       -> Customer notifications
          

CDN and edge protection

A content delivery network serves images, stylesheets and scripts from locations closer to users, and edge protection can filter malicious or excessive traffic before it reaches your services. Slow-changing product data can be cached too, but a cached stock value is never the final word. Checkout must revalidate.

API gateway and load balancing

A gateway gives requests a controlled entry point for authentication, limits and routing. A load balancer spreads requests across healthy instances. More instances help only if databases and payment services can take the load behind them, and scaling the web tier does nothing for contention on the last few units.

Browsing and checkout as separate workloads

Browsing is read-heavy. Checkout changes business records and decides on stock, price, delivery and payment. A good design keeps product-page views away from expensive stock locks. Our monolith to microservices guide covers splitting a single application into services.

Inventory reservation service

This service decides whether a unit can be held for a checkout session, using concurrency-safe operations, and records which session owns the hold. A reservation needs an expiry policy, or abandoned checkouts block stock indefinitely. Expiry must also respect payment status: a browser timeout does not prove a payment failed.

Stock accuracy also depends on warehouse scans and adjustments, so warehouse and inventory systems belong in any checkout reliability review.

Order management service

This service tracks business state, through states such as PENDING_PAYMENT, PAYMENT_CONFIRMED, CONFIRMED, CANCELLED and REFUND_PENDING. The names vary. What matters is that each state has one clear meaning and that invalid transitions are rejected.

Message queue and asynchronous work

Warehouse tasks, notifications and analytics do not need to block the checkout response. A queue decouples these services and absorbs bursts, but it does not guarantee correctness. Consumers still need retries, duplicate handling, monitoring and a way to recover messages that cannot be processed.

When payment succeeds but the order is cancelled

A customer sees a product as available, pays, and a few minutes later is told the order is cancelled and a refund has started. This is a poor experience and may point to a design problem, but it does not by itself prove a software defect or a deliberate practice. Only the order, stock, payment and fulfilment records can show the cause.

Possible cause What may have happened What to check
Stale stock data The displayed quantity was not the current sellable quantity Update times, source-of-truth records, checkout validation logs
Concurrent attempts Several checkouts tried to claim the last unit Reservation records, transaction results, oversell metrics
Seller or warehouse issue Stock was missing or damaged, or the seller could not supply it Seller acceptance, warehouse scans, stock adjustments
Late payment status The bank confirmed after the application timed out Provider status, webhook history, order state changes
Order service failure Payment succeeded but the order was not recorded Service logs, event delivery, retries, reconciliation
Fulfilment or policy check A delivery, fraud or compliance check blocked the order The specific rejection reason and policy applied

Why a payment can succeed when an order cannot be confirmed

Checkout spans systems that do not update at the same instant: order service, stock service, payment gateway, acquiring bank, issuing bank and fulfilment.

A timeout means the application did not get a final answer in time. It does not mean the payment failed. Razorpay's guide makes the distinction: a timeout is the gateway not hearing from the bank within the expected window, and late authorisation is that answer arriving afterwards and confirming success. It recommends updating order status from server-to-server events, because a customer who closes the tab never triggers the browser redirect.

A typical sequence looks like this:

  1. The customer starts checkout and the platform creates a pending order.
  1. The request reaches the payment provider and the bank processes it, but the response is delayed.
  1. The application times out and shows a pending or failed-looking state.
  1. The successful status arrives later through the provider.
  1. The order service must now reconcile the payment with the order and the reservation.

If the application treats the timeout as failure, it releases the stock and another customer may buy it. When the first payment then succeeds, the platform must either find stock or reverse the payment.

Razorpay's guidance turns on whether you can still provide the service. If you can, keep the order pending and fulfil it when the payment is authorised. If you cannot, let the payment lapse and tell the customer it will be returned. Its timeout guide suggests defaulting to a refund for categories such as food delivery and ticketing, where the service cannot wait.

Should the platform collect payment before confirming stock?

No. Reserve stock before asking the customer to pay. A stock check alone is not enough, because it does not hold the unit for that attempt.

A practical sequence:

  1. Revalidate price, seller, delivery eligibility and sellable stock.
  1. Create a temporary reservation for the requested quantity.
  1. Create or update a pending order linked to that reservation.
  1. Start the payment.
  1. Verify the final status using trusted server-side information.
  1. If payment succeeds, commit the allocation and confirm the order.
  1. If payment definitely fails, or checkout expires without a successful payment, release the reservation.
  1. If the status is uncertain, reconcile before deciding whether to release stock or reverse the payment.

This reduces the chance of charging for stock already allocated elsewhere. It cannot remove every cancellation, because seller failures, warehouse discrepancies and fraud checks still happen.

Reservation and final allocation are different steps

A temporary reservation holds stock for a limited period during checkout. A final allocation commits it to a confirmed order. Shopify uses the same split: it reserves when payment starts, as a hold of several minutes, and claims against the ledger when payment succeeds.

Set the hold from observed payment behaviour, not a universal number. If status is still unknown when a hold ends, follow a defined grace period and reconciliation policy rather than releasing stock at the first timeout.

Authorisation and capture are not universal

Some providers and payment methods separate authorisation from capture, so a merchant can authorise first and capture after stock and order checks pass. Razorpay's guide says manual capture gives the backend the final say on whether to claim or reverse funds. UPI, cards, wallets and net banking do not all behave the same way, so follow your provider's contract for each method.

The choice has consequences. On Razorpay, only payments in the authorised state can be auto-refunded, including those not captured within the capture timeout, which is 3 days by default. Captured payments are refunded only when the merchant starts a refund or loses a dispute. Auto-capture therefore puts refund handling on you.

How to recover from a partial failure

A distributed checkout cannot always run as one database transaction, because stock, orders and payments may belong to different services.

The saga pattern is one established way to coordinate this. AWS describes a saga as a sequence of local transactions, where a failure triggers compensating transactions for the earlier steps.

Step Normal action Recovery action
1 Reserve stock Release the reservation if checkout definitely fails
2 Create pending order Cancel the order if payment cannot complete
3 Process payment Void the authorisation or refund, where supported
4 Confirm allocation Reconcile or reverse if confirmation cannot proceed
5 Publish fulfilment event Retry safely or park the event for investigation

Compensation is not always a rollback. A refund is a new payment operation and does not erase the original bank transaction, so keep the full history of the payment, the refund request and the final refund status.

Make retries safe with idempotency

An operation is idempotent when repeating it has no unintended extra effect, which is what makes a client retry safe. A customer clicks Pay, the browser times out and the customer tries again, while the first attempt may still succeed. Without controls, that retry can create a second payment or duplicate order activity.

Use a stable order or checkout identity, and enforce uniqueness at the business level for allocation and fulfilment. Razorpay's timeout guide recommends tying payment requests to a key such as the order ID. Our guide to idempotency keys for safe retries covers the pattern in detail.

Check the provider's contract rather than assuming one header works everywhere. Razorpay documents operation-specific headers, such as X-Refund-Idempotency for normal and instant refunds, and says these do not establish a universal header for every endpoint. It also auto-refunds a duplicate payment made on an order already marked as paid. Teams routing through several providers need to check this for each one; see our multi-PSP checkout guide.

Use webhooks and reconciliation together

A webhook is a server-to-server notification of a payment event. It keeps working when the customer closes the browser, but it does not promise exactly-once or in-order delivery. Razorpay states that it uses at-least-once delivery, resends an event if your server does not respond within 5 seconds, and may not deliver events in order.

So the receiving application should:

  • verify the webhook signature before trusting the event;
  • store accepted events durably, then acknowledge quickly and do slow work asynchronously;
  • deduplicate on the event ID, which Razorpay sends in the x-razorpay-event-id header;
  • reject events that would make an invalid state change, such as moving a captured payment back to authorised;
  • make fulfilment and refund actions idempotent; and
  • reconcile unresolved orders against the provider's records on a schedule.

Reconciliation should catch these cases:

  • payment captured, but order still pending;
  • order confirmed, but payment not confirmed;
  • payment succeeded after the reservation expired;
  • refund requested, but status unresolved; and
  • several payment attempts against one checkout.

The aim is not to hide failures. It is to make every transaction traceable and bring order, stock and payment records to a known final state.

What this means for reported sales

A platform may record a successful payment before a later cancellation and refund. That is not a completed sale, and it is not revenue of the same amount.

Measure Amount
1,000 captured payments of ₹50,000 each ₹5 crore
200 orders later fully refunded ₹1 crore
Captured amount left after those refunds ₹4 crore

This is illustrative arithmetic, not a report about any company, and it does not set the accounting treatment for a marketplace. Gross merchandise value, collections, refunds, seller settlements and recognised revenue are different measures, and the right treatment depends on the business model and accounting policies.

A dashboard should keep these separate: payment attempts, authorisations and captures, confirmed orders, cancelled orders, refund requests and completions, delivered units, and net sales after adjustments.

Refunds also create work in support, reconciliation and seller communication, and may carry provider charges under your contract.

Nothing in the sources cited here suggests that Flipkart or Amazon deliberately takes payment for products it cannot supply, and such a claim would need direct evidence. The conclusion we can support is narrower: paid-then-cancelled orders create avoidable cost and damage trust, so platforms should keep them rare and report them openly.

How to measure checkout reliability

Traffic capacity is only part of a good sale. A checkout can serve huge request volumes and still fail customers if allocation or reconciliation is unreliable.

Metric What it reveals
Reservation success rate Whether valid requests can secure stock
Oversell rate How often more units are promised than can be supplied
Payment-to-order time How long a successful payment takes to become a confirmed order
Paid-but-cancelled rate How often successful payments end in cancelled orders
Unresolved payment rate How many payments stay pending past the expected window
Duplicate payment rate Whether retries or errors cause multiple successful payments
Refund start and completion time How well refunds are handled
Inventory accuracy Whether system stock matches physical stock
Checkout conversion rate Whether reliability problems stop purchases

Segment these by seller, warehouse, category, payment method and traffic period. A platform-wide average can hide a serious problem with one seller or one payment method.

What to test before a major sale

Treat a large sale as a planned operational event, and test failure as well as load:

  1. Concurrent last-unit purchases: send many simultaneous requests for a small quantity and confirm reservations never exceed sellable stock.
  1. Reservation expiry: abandon sessions and confirm stock is released according to policy.
  1. Delayed payment responses: simulate a payment that succeeds after the client-side timeout.
  1. Duplicate webhooks: deliver an event more than once and confirm nothing is fulfilled or refunded twice.
  1. Out-of-order events: send events in an unexpected sequence and confirm invalid changes are rejected.
  1. Order service interruption: take it down after payment success and confirm reconciliation recovers the transaction.
  1. Inventory service interruption: confirm checkout fails safely rather than selling without a reservation.
  1. Refund recovery: time out a refund request and confirm the system finds its real status before retrying.
  1. Queue backlog: slow the workers and confirm orders and events stay durable and visible.
  1. Customer messages: test the wording for pending payment, confirmed payment, cancellation and refund.

AWS reports testing failure on purpose at very large scale. It says more than 44,000 AWS Fault Injection Service experiments were run ahead of Prime Day 2026, more than six times the 2025 number. That shows the scale of resilience testing. It does not disclose Amazon's retail checkout design, and it is not a measure of checkout reliability.

A successful payment is not a successful order

The hard part of e-commerce system design is not only serving millions of visitors. It is making sure a product is available, the customer gets a valid payment outcome, stock is allocated correctly and the order can be fulfilled.

A well-designed checkout validates stock at the point of purchase, reserves it safely, records payment and order states independently, and recovers cleanly when one service fails. Timeouts are reconciled rather than assumed to be failures, and retries never create duplicate charges, orders or shipments.

How eCorpIT can help

eCorpIT is a Gurugram-based technology organisation, founded in 2021, assessed at CMMI Level 5 and MSME certified, with senior-led engineering teams working across AWS, Microsoft and Google platforms. Our e-commerce app development team can review your checkout, stock reservation and payment reconciliation design and test it against failure scenarios like these before a major sale. Talk to us at /contact-us/.

Last updated: 3 November 2026.

References

  1. Late Payment Authorisations — Razorpay Docs
  1. India Logs on for The Big Billion Days: Flipkart Records 6.3 Million Concurrent Users as the Festive Season Opens, 9 October 2026 — Flipkart Stories
  1. Amazon Prime Day 2025: Top products from India's record-breaking sale — About Amazon India
  1. Personalization, Innovation and Customer First, Q&A with Jeyandran Venugopal, 13 October 2023 — Flipkart Stories
  1. Prime Day 2026 India highlights: Fastest ever with deliveries in minutes and record deals — About Amazon India
  1. We replaced Redis with MySQL for inventory reservations, and it scaled, 12 May 2026 — Shopify Engineering
  1. Locking Reads, MySQL 8.0 Reference Manual — MySQL
  1. Payment Timeout vs. Late Authorisation: A Merchant's Guide to Handling Delayed Payments, 17 September 2026 — Razorpay Learn
  1. Handle Late Authorised Payments — Razorpay Docs
  1. Payment Capture Settings — Razorpay Docs
  1. Auto-Refunds — Razorpay Docs
  1. Saga patterns — AWS Prescriptive Guidance
  1. Making retries safe with idempotent APIs — AWS Builder Center
  1. Payment Gateway Webhooks in India: Signature Verification, Retries and Event Logs, 27 October 2026 — Razorpay Blog
  1. Webhooks Best Practices — Razorpay Docs
  1. AWS Weekly Roundup: Prime Day 2026 by the numbers, 13 October 2026 — AWS News Blog

Frequently asked

Quick answers.

01 What makes a flash sale hard for an e-commerce system?
Demand arrives in a sharp burst, and many customers try to buy the same limited stock at once. The site must stay up, but it must also allocate each unit once, take the right payment and confirm the order. Adding web servers helps with traffic but does not solve stock contention or payment correctness.
02 How do you stop overselling during a flash sale?
Make the stock decision a concurrency-safe operation at checkout, not a separate read followed by a write. A conditional atomic update works at low volume. At high volume a single row becomes a bottleneck, so some platforms, including Shopify, keep one row per unit and let transactions skip rows that are locked.
03 Should stock be reserved before or after payment?
Before. Validate price and availability, place a temporary reservation, link it to a pending order, and only then start the payment. When payment succeeds, commit the allocation and confirm the order. This greatly reduces charges for unavailable stock, although seller failures, warehouse errors and fraud checks can still cause a later cancellation.
04 How long should a stock reservation last?
There is no universal number. Shopify describes a short hold of several minutes while payment runs. Set your own hold from observed payment times for each method, and define a grace period for unknown results. Too short risks releasing stock that was paid for, and too long keeps stock from other buyers.
05 What is a late authorised payment?
It is a payment where the bank's success response reaches the gateway after the expected window has passed, so checkout may already have shown a failure. Razorpay says fewer than 0.5% of its payments behave this way. The merchant then either fulfils the pending order or returns the money to the customer.
06 Why can a customer be charged when the order fails?
Checkout spans the order service, stock service, gateway and banks, and they do not update together. A payment can succeed while the order service is down, or arrive after a timeout released the stock. Only the actual records show the cause, so reconcile them before calling it a payment, stock or order failure.
07 Are payment webhooks enough to confirm an order?
Not alone. Webhooks are more reliable than a browser redirect, but delivery can repeat or arrive out of order. Verify the signature, store each event durably, deduplicate by event ID and reject invalid state changes. Then reconcile unresolved orders against the provider's records on a schedule, so that a missed event still gets resolved.
08 Do Flipkart and Amazon use this exact architecture?
We cannot say. Both publish scale figures, but neither discloses its full checkout design, so this article does not claim which databases, brokers or payment sequences they use. The architecture here is a generic reference, and the Shopify and Razorpay details are documented by those companies about their own systems and products.

About the author

Aman Mathur

Software Engineer | Flutter

Software Engineer with 3+ years building high-performance, AI-powered cross-platform mobile apps for global clients.

Subscribe

One engineering note a week. No fluff, no spam.

Senior-architect playbooks on AI agents, mobile apps, cloud, security, data, and marketing — delivered every Wednesday.

Past the reading

Read enough. Let's build something.

A senior architect responds in 24 working hours with scope, indicative cost, and a timeline. NDA before any technical conversation.