Interview Prompt
Design a platform where users can browse events, select seats, reserve tickets, and complete purchase during high-demand sales.
Identifies ticket inventory as the consistency-critical part of the system.
Uses temporary holds with expiration instead of charging immediately.
Protects the system with waiting rooms, rate limits, and bot controls.
Handles payment authorization, order confirmation, and hold release.
Step 1
Clarify functional and non-functional requirements first.
Functional Requirements
- Users can browse events, venues, sections, and available seats.
- Users can select seats and place a short-lived hold.
- Users can complete payment before the hold expires.
- The system issues tickets and sends confirmation.
- The platform supports high-demand onsales with waiting rooms.
Non-Functional Requirements
- Never sell the same seat twice.
- Seat availability should be reasonably fresh during normal browsing.
- Checkout should remain consistent even under extreme load.
- The system should defend against bots and abusive purchase patterns.
- Payment failures should release inventory reliably.
Scale Assumptions
- A major event has 80,000 seats.
- 1 million users may enter the waiting room for a popular onsale.
- Seat map browsing may be 100 times larger than completed purchases.
- A hold lasts 5 to 10 minutes.
Inventory writes
Bounded by seats
The number of successful holds cannot exceed event inventory, but attempts can be enormous.
Waiting room
Millions of users
Queue service must absorb traffic before users reach seat selection.
Seat reads
Very high burst
Seat maps and availability snapshots are the main read load.
Hold expiration
Continuous background work
Expired holds must return seats to available inventory without manual cleanup.
Step 2
Identify the key entities before picking storage.
| Entity | Fields and Relationships | Interview Notes |
|---|---|---|
| Event | event_id, venue_id, name, start_time, sale_state | Sale state controls browsing, waiting room, and checkout behavior. |
| SeatInventory | event_id, seat_id, status, hold_id, version | The consistency-critical row. Use conditional updates or transactions. |
| Hold | hold_id, user_id, seat_ids, expires_at, status | Expires automatically and releases seats if not converted. |
| Order | order_id, user_id, hold_id, payment_id, status | Tracks payment and ticket issuance lifecycle. |
Step 3
Define the APIs around the user flows.
| Interface | Request / Response | Contract Notes |
|---|---|---|
| GET /v1/events/{eventId}/availability | Returns section availability or seat-level snapshot | Serve cached snapshots and refresh frequently during onsales. |
| POST /v1/holds | { eventId, seatIds, idempotencyKey } -> { holdId, expiresAt } | Atomic inventory transition from available to held. |
| POST /v1/orders | { holdId, paymentMethodId } -> { orderId, status } | Authorize payment, capture if required, then confirm tickets. |
| POST /v1/waiting-room/join | { eventId } -> { positionToken } | Controls admission into inventory-sensitive endpoints. |
Step 4
Trace the critical data flow step by step.
Waiting room
Users first enter a queue that meters traffic into seat selection and reduces bot-driven request spikes.
Availability read
Clients browse cached section or seat snapshots. Exact truth is checked only during hold creation.
Hold seats
Inventory service atomically changes selected seats from available to held with a hold expiration timestamp.
Checkout
Order service validates hold ownership and expiry, authorizes payment, confirms inventory, and issues tickets.
Expiration and recovery
Background workers release expired holds and reconcile payments, orders, and inventory transitions.
Step 5
Convert the flow into a high-level design.
Final Design
Ticketing Platform final architecture
Serving Layer
Start with clients, routing, APIs, and the main synchronous path users depend on for this problem.
State Layer
Anchor the design around the key entities: Event, SeatInventory, Hold, Order.
Async Layer
Move slow, high-volume, or failure-prone work behind queues, workers, streams, caches, or background reconciliation.
Step 6
Deep dives interviewers are likely to probe.
Inventory correctness
- Use conditional updates on seat status and version to prevent double sell.
- Seat selection can show stale data, but hold creation must be strongly consistent.
- Holds should expire even if checkout workers fail.
Waiting room design
- Queue tokens should be signed and short lived.
- Admission rate should adapt to checkout capacity and payment provider health.
- Users should not refresh their way to a better position.
Payments
- Use idempotency keys for payment attempts.
- Do not confirm tickets until payment authorization or capture succeeds.
- Reconciliation jobs should detect paid orders without issued tickets and held seats without orders.
Step 7
Tradeoffs to explain out loud.
Cached availability vs exact availability
Use When
Cache browse views to handle high read volume.
Watch Out
Users may see seats that fail during hold creation.
Seat-level inventory vs section-level inventory
Use When
Seat-level is required for assigned seating.
Watch Out
General admission can use simpler counters but still needs atomic decrement.
Long holds vs short holds
Use When
Short holds increase inventory turnover and reduce abandoned carts.
Watch Out
Too-short holds frustrate users during payment or account friction.
Avoid
Common mistakes that weaken the answer.
- Using cache availability as the source of truth for purchase.
- Not expiring holds reliably.
- Charging payment before inventory is reserved.
- Ignoring bot traffic and waiting room admission.
- Allowing checkout retries to create duplicate orders.
Step 8
Follow-up questions with strong answers.
How do you guarantee a seat is not sold twice?
Make inventory transition atomic with conditional update or transaction on seat status/version, and only issue tickets after the held seat is confirmed for one order.
What if payment succeeds but ticket issuance fails?
Keep order in a pending-confirmation state, retry issuance idempotently, and run reconciliation before releasing inventory or refunding.
How do you handle bots?
Use waiting room tokens, rate limits, device and account reputation, CAPTCHA for suspicious flows, purchase limits, and fraud review.
Step 9
What a strong answer should signal.
Consistency
Clearly identifies atomic inventory hold as the critical guarantee.
Traffic control
Uses waiting rooms and cached availability to survive flash-sale load.
Payments
Handles idempotency, authorization, capture, confirmation, and reconciliation.
Edge cases
Covers hold expiry, stale maps, bots, cancellations, and partial failures.
Practice this problem under interview conditions.
Read the guide, then run the prompt live with LeetSys so you can practice requirements, key entities, API design, data flow, whiteboarding, tradeoff narration, and follow-up handling.
Related Guides
Senior
News Feed
A complete system design guide for building a personalized social news feed with fanout, ranking, privacy, and timeline freshness tradeoffs.
Senior
Video Streaming
A senior-level guide to designing a YouTube-style video streaming system with uploads, transcoding, CDN delivery, metadata, search, and recommendations.
Senior
Real-Time Chat
A practical chat system design guide covering WebSockets, message ordering, delivery receipts, offline sync, group chats, and end-to-end reliability.