Design problems
E-commerce & marketplacesHardSDE-2 40 min

Design an e-commerce platform (Amazon / Flipkart)

Asked at
AmazonFlipkartMeeshoMyntraNykaaWalmart Global Tech

The interviewer asks

“Design the core of an e-commerce marketplace like Amazon or Flipkart: users browse products, add them to a cart, check out and pay, and track their orders. Many sellers list products and ship from several warehouses.”

What a strong answer looks like

A strong answer scopes the platform into bounded services and spends its time on the order path. Browsing is read-heavy and served from caches, a CDN and a search index fed by CDC from the catalogue. The cart is a per-user key-value document. Checkout is the hard part: it re-prices the cart, reserves inventory with a short TTL, creates an order in a PENDING state with an idempotency key, and hands off to the payment service; payment success or failure drives the order through a state machine via events, with a saga that releases stock or refunds on failure. The order database is relational and sharded by user or order ID; downstream work (seller notification, invoicing, shipping, emails) is async via Kafka using the transactional outbox. Strong candidates give numbers for normal days vs Big Billion Days, never oversell, never double charge, and explain what is strongly consistent (stock, money, order state) and what can be eventually consistent (search, recommendations, reviews).

Concepts to mention

Order state machineSaga with compensations (orchestrated)Idempotency keys end to endStock reservation with TTL and conditional updateTransactional outbox to KafkaSharded relational order storeRead-heavy browse with CDN and cachesPayment webhook handling and reconciliationGraceful degradation and feature flags on sale days

1 Requirements

Functional

  • Browse categories, search products and view product pages with price, offers and delivery date
  • Add, update and remove items in a cart that persists across devices
  • Checkout: choose address, see final price with taxes and delivery fee, pay (UPI, cards, wallets, COD)
  • Create orders that may split into shipments from different sellers and warehouses
  • Order tracking and history; cancel and return flows
  • Sellers manage listings, price and stock, and receive orders

Non-functional

  • Product page p99 under 200 ms; checkout API p99 under 1 s excluding the payment provider
  • Normal ~5k orders/min; sale peak ~20x (Big Billion Days first hour)
  • No overselling of stock and no double charging, even with retries
  • Order and payment data strongly consistent and durable (RPO ~0)
  • Availability 99.95% for browse and 99.99% target for checkout
  • Data for Indian users stored in India (payment data under RBI localisation rules)

Out of scope (say it out loud)

  • Search ranking details (see product-search)
  • Recommendations (see recommendation-system)
  • Warehouse management internals (see inventory-management)
  • Payment gateway internals (see payment-gateway)
  • Last-mile logistics

2 Estimates

Users~100M MAU, ~15M DAU (~60M on sale days)Large Indian marketplace; sale days bring 3-4x DAU
Orders~7M/day normal (~80/s), peak ~1,500-2,000/s7M / 86,400 ~ 80/s average; sale opening minute concentrates demand ~20x on top of a higher daily base
Product page views~50k/s peak reads~100 page views per order x 2,000 orders/s at peak / 4 (cache and CDN absorb the rest at the edge) ~ 50k/s hitting services
Read:write ratio~100:1 or moreBrowsing dominates; carts and orders are a small share of requests
Order storage~7 TB/year7M orders/day x ~3 KB (order + items + addresses + status history) x 365 ~ 7.7 TB/year before replicas
Catalogue~200M SKUs, ~200 GB metadata~1 KB per SKU; images in object storage behind a CDN (~100s of TB)

3 API

EndpointWhat it does
GET/v1/products/{id}?pincode=560001Product page: details, price, offers, stock status and delivery estimate for the pincode
PUT/v1/cart/items/{sku_id}Set quantity of an item in the user's cart (0 removes)
POST/v1/checkoutValidate cart, re-price, reserve stock, create a PENDING order; header Idempotency-Key; returns order_id and payment session
POST/v1/payments/callbackWebhook from payment service/gateway with the payment result (signed, idempotent)
GET/v1/orders/{order_id}Order status with shipments and tracking
POST/v1/orders/{order_id}/cancelCancel items not yet shipped; triggers refund and stock release

4 Data model

catalog_productsMySQL/Postgres sharded, or a document store
product_idtitlebrandcategoryattributes JSONimages[]seller_id

Source of truth for listings; cached heavily in Redis and CDN; streamed to search via CDC.

listing_offersPostgres + Redis cache
sku_idseller_idpricemrpstatus

Price is read from here at checkout, never trusted from the client.

cartsRedis (with persistence) or DynamoDB/Cassandra
user_id (key) -> {items: [{sku_idqtyadded_priceadded_at}]updated_at}

Simple key-value access by user. Guest carts keyed by device ID are merged at login.

ordersPostgres/MySQL sharded by user_id (or Vitess)
order_id (PK, time-ordered ID)user_idstatustotalcurrencyaddress_ididempotency_key (unique per user)payment_idcreated_atversion

Relational: needs transactions with order_items and outbox rows. Shard by user_id so 'my orders' is a single-shard query; order_id encodes the shard.

order_items / shipmentsSame shard as orders
order_iditem_idsku_idseller_idwarehouse_idqtyunit_priceshipment_iditem_status

Items are grouped into shipments by seller and warehouse.

outboxSame database as orders
event_idaggregate_idtypepayloadcreated_atpublished

Written in the same transaction as the order change; a relay (Debezium) publishes to Kafka.

inventoryInventory service DB (Postgres) + Redis counters for hot SKUs
sku_idwarehouse_idavailablereserved

See inventory-management. Reservations have a TTL (~10-15 min).

5 Architecture

CLIENTSEDGESERVICESASYNCDATAEXTERNALimagesAPI callsbrowse / searchcheckoutcachereserve stockorder + outboxpayment sessionwebhook resultoutbox relaycommit / releasecreate shipmentWeb / mobile appCDN (images, static)API gatewayInventory serviceCheckout / orderserviceCart serviceCatalogue + searchKafka (order events)Fulfilment, notify,invoiceOrders DB (shardedSQL)Redis (carts, cache)Catalogue DB + ESPayment service / PGLogistics partners
ClientEdge / gatewayService / workerQueue / streamCacheDatabase / storageAI / modelThird partyrequestasync (event / queue)

Hover a box to highlight its connections.

6 Request flows

Checkout and pay

  1. 1User taps 'Place order'; the app sends POST /v1/checkout with an Idempotency-Key generated once for this attempt.
  2. 2Checkout service loads the cart, re-reads current prices and offers from the server side, recomputes taxes and delivery fee and shows a changed price if anything moved.
  3. 3It asks the inventory service to reserve each SKU at a chosen warehouse (conditional decrement of available, increment of reserved) with a 15-minute TTL.
  4. 4In one DB transaction it inserts the order (status PENDING_PAYMENT), order items, and an outbox event OrderCreated; the unique (user_id, idempotency_key) index makes a retried request return the same order.
  5. 5It creates a payment session with the payment service using order_id as the merchant reference and returns the payment details to the app.
  6. 6User pays via UPI/card; the payment service sends a signed webhook. Checkout verifies it, and in one transaction moves the order to CONFIRMED (only if still PENDING_PAYMENT, checked by version) and writes an OrderConfirmed outbox event.
  7. 7Consumers of OrderConfirmed: inventory converts reservations into committed deductions, the seller service notifies sellers, invoicing generates GST invoices, notifications send SMS/push, and fulfilment creates shipments with logistics partners.
  8. 8If payment fails or the reservation TTL expires first, the order moves to CANCELLED and an event releases the reserved stock; a late successful payment for a cancelled order triggers an automatic refund.

View a product page

  1. 1Images and static assets come from the CDN.
  2. 2Gateway calls the product page aggregator, which fetches product details (Redis cache, ~95% hit), the best offer and price, stock status and the delivery promise for the pincode in parallel.
  3. 3Each dependency has a timeout; if offers or delivery estimates are slow, the page renders without them rather than failing.
  4. 4Response is assembled and returned in under ~150 ms.

7 Deep dives

The order state machine and the checkout saga

An order touches services that cannot share one database transaction: inventory, payment, order, and later fulfilment. Use a saga: a sequence of local transactions with compensations. The order service owns a state machine: CREATED -> PENDING_PAYMENT -> CONFIRMED -> PACKED -> SHIPPED -> DELIVERED, with side branches CANCELLED, PAYMENT_FAILED, RETURN_REQUESTED, REFUNDED. Every transition is a conditional update (UPDATE ... WHERE id = ? AND status = 'PENDING_PAYMENT' AND version = ?), so two concurrent events cannot both win. Compensations: payment failed -> release reservation; reservation expired before payment -> cancel order and auto-refund any late payment; seller cannot fulfil -> cancel that item, refund, and offer an alternative seller. Orchestration (the order service or a Temporal workflow drives steps) is easier to reason about and debug for checkout than pure choreography. Every external call carries the order_id as an idempotency key, so retries after timeouts are safe. Finally, run a reconciliation job that compares orders with payment provider settlement reports every few hours to catch anything a lost webhook missed.

Idempotency and the double-click problem

Mobile networks in India drop requests often. A user taps 'Pay', the request reaches the server, the response is lost, and the app retries. Without protection you get two orders and maybe two charges. Three layers stop this. First, the client creates an Idempotency-Key per checkout attempt and resends it on retry; the server stores (user_id, key) with a unique constraint and returns the stored response for repeats. Second, payment calls use order_id as the merchant reference so the payment provider rejects a second payment intent for the same order. Third, the webhook handler is idempotent: it records payment_id as processed and ignores duplicates, because providers deliver webhooks at least once. Also handle the case where the user gives up and retries with a new key: the app shows the existing pending order instead of creating a new one when the cart has not changed. Saying 'exactly-once delivery does not exist end to end; we make every step idempotent' is what interviewers want to hear.

Reserving stock without overselling

Stock must never go below zero, but locking a row for the whole payment (which can take minutes with UPI) would kill throughput. So checkout reserves: a single atomic conditional update such as UPDATE inventory SET available = available - :qty, reserved = reserved + :qty WHERE sku_id = :sku AND warehouse_id = :wh AND available >= :qty. If zero rows change, the item is out of stock at that warehouse and the service tries the next nearest warehouse. A reservation row records order_id, quantity and expires_at. On payment success the reservation is committed (reserved decreases, the item is gone); on failure or expiry a sweeper releases it back to available. For a few extremely hot SKUs during sales, a single row becomes a hot spot; those are handled by the flash-sale design (Redis counters, token buckets, queues). Mention that 'add to cart' does not reserve stock: carts are wish lists, and reserving at cart time lets bots lock up inventory.

Service boundaries and data ownership

Split by business capability, each service owning its data: catalogue (listings, content), pricing and offers, inventory, cart, order, payment, fulfilment, user and address, seller. Do not let services read each other's tables; they call APIs or consume events. Reads that combine data (the product page, 'my orders' with tracking) are built by an aggregator or by read models fed from events, so the order service is not called with heavy joins for every page view. Consistency needs differ: money, order state and stock need strong consistency inside their owner; search, recommendations, review counts and analytics can lag by seconds or minutes. The transactional outbox keeps events and state changes atomic without two-phase commit. In an interview, do not draw 30 microservices; draw the 5-6 that matter for the order path and say the rest exist.

8 Trade-offs

SQL vs NoSQL for orders

Orders need multi-row transactions (order, items, outbox), constraints (unique idempotency key) and flexible queries for support tools, so a relational DB sharded by user_id (or a distributed SQL like Vitess/TiDB) fits. Carts and sessions are simple key lookups, where Redis or DynamoDB is cheaper.

Orchestrated vs choreographed saga

Orchestration puts the checkout logic in one place with clear state and timeouts, ideal for the critical path. Choreography (services react to events) is fine for side effects like emails, invoices and analytics, where no central decision is needed.

Reserve at checkout vs at add-to-cart vs at payment

Reserving at add-to-cart lets carts hoard stock; reserving only after payment risks taking money for items that are gone. Reserve at checkout with a short TTL; refund automatically in the rare race.

Monolith first vs microservices

A modular monolith is faster to build for a startup; at Flipkart scale independent scaling and deploys of catalogue, cart and order justify services. Mention the cost: distributed transactions and harder debugging.

9 Bottlenecks

Sale-day traffic

20x spikes at fixed times. Pre-scale stateless services and database capacity, warm caches, put a virtual waiting room in front of checkout, and turn off non-essential features (recommendations, reviews) with flags to protect the order path.

Hot SKUs in inventory

A single phone launch can get 100k checkout attempts per second on one row. Move that SKU to a Redis-based counter with admission control; see the flash-sale design.

Order DB write load

Shard by user_id; keep transactions small; move status-history writes and analytics to async consumers. Order lookup by order_id works because the ID encodes the shard.

10 Failure handling

Payment webhook never arrives

Order stays PENDING_PAYMENT. A poller queries the payment service for orders pending more than a few minutes, and the reconciliation job checks settlement files. The reservation TTL is longer than the payment window to avoid cancelling a paid order.

Kafka or consumers down

Order state is already committed with an outbox row; events are published when the relay recovers. Downstream steps are delayed, not lost. Consumers are idempotent by event_id.

Inventory service unavailable

Checkout cannot safely reserve, so it fails fast with a clear message rather than overselling; browse and cart keep working. Circuit breakers stop retry storms.

11 What impresses

  • Stating which data needs strong consistency and which can be eventual
  • Explaining the late-payment-after-cancel race and auto refund
  • Idempotency at client, order and payment webhook levels
  • Reconciliation with the payment provider as a safety net
  • Server-side re-pricing at checkout; never trusting client prices
  • Load-shedding non-critical features to protect checkout during sales

12 Mistakes

  • Using a single distributed transaction (2PC) across inventory, payment and orders
  • Reserving stock at add-to-cart
  • No idempotency, so retries create duplicate orders or charges
  • Drawing dozens of microservices without explaining the order path
  • Assuming the payment webhook always arrives exactly once
  • Reading another service's database directly

13 Follow-ups

Q1How do you split one order into shipments from three sellers, and what if one cancels?
Q2How does Cash on Delivery change the flow?
Q3How would you implement returns and refunds?
Q4How do you show an accurate delivery date on the product page?
Q5How do you keep the cart price and checkout price consistent when offers change?
Q6What changes if you must run active-active across two regions?

Practice questions

Saved on this device. Create a free account to keep it on every device.

Practise this with Sam

A real mock interview, out loud, with an honest scorecard. Free to start.

Start free