AceTheOffer
Case StudiesAdvanced

Design a Ticket Booking System

Practice a ticket-booking design with inventory holds, concurrent purchases, payment confirmation, expiration, fairness, and oversell prevention.

14 min readUpdated August 22, 2026

What you'll learn

Run the architecture drill

  • How to model inventory, short-lived holds, orders, and confirmed tickets separately.
  • Why oversell prevention needs an authoritative concurrency boundary.
  • How payment uncertainty and hold expiration interact in a realistic booking flow.

A ticket booking system is a concurrency and correctness problem disguised as a shopping flow. Its central challenge is giving users a fair reservation experience while preventing two buyers from successfully purchasing the same scarce inventory during traffic spikes, payment uncertainty, and hold expiration.

Start with the architecture drill, then follow the request path through scale, failure, and a defensible interview answer.

Interview reasoning

Make your assumptions and decision path easy to inspect.

ATOFF architecture reasoning canvas

Design a Ticket Booking System: the architecture drill

Short answer

A ticket booking system protects scarce inventory with one authoritative allocation decision, bounded holds, and a payment-finalization flow that cannot oversell.

10× evolution

Introduce a waiting room and partition allocation without splitting a seat's authority.

3 checkpoints
  1. 01

    Decision checkpoint

    Design brief

    Allocate a seat through conditional state transition or serialized ownership so no two successful orders can claim the same unit.

  2. 02

    Decision checkpoint

    First request path

    A hold needs an expiry, owner, and visible countdown; releasing it must be idempotent because expiry and payment callbacks race.

  3. 03

    Decision checkpoint

    Failure drill

    Treat payment confirmation as an event that attempts to convert a still-valid hold, then reconcile late or uncertain outcomes without selling twice.

Say it in the interview

I would state the no-oversell invariant, use expiring holds for fairness, and make payment confirmation a conditional finalization rather than a blind update.

  1. 1

    Buyer

    browse: Availability view · request hold: Inventory command conditional update

  2. 2

    Availability view

  3. 3

    Inventory command conditional update

    reserve if available: Expiring seat hold

  4. 4

    Expiring seat hold

    hold ID + deadline: Idempotent payment attempt · deadline: Hold expiry worker

  5. 5

    Idempotent payment attempt

    successful outcome: Confirm transaction order + ticket

  6. 6

    Confirm transaction order + ticket

    sell once: Confirmed ticket

  7. 7

    Confirmed ticket

  8. 8

    Hold expiry worker

    release if unconfirmed: Inventory command conditional update

Ticket booking lifecycle protects scarce inventory through an expiring hold. Browsing availability is separate from the authoritative hold command. A short-lived hold gives payment a bounded window; only a successful payment plus inventory transition creates a ticket, while expiry safely releases the inventory for another buyer.
  1. Buyer flows to Availability view via browse.
  2. Buyer flows to Inventory command conditional update via request hold.
  3. Inventory command conditional update flows to Expiring seat hold via reserve if available.
  4. Expiring seat hold flows to Idempotent payment attempt via hold ID + deadline.
  5. Idempotent payment attempt flows to Confirm transaction order + ticket via successful outcome.
  6. Confirm transaction order + ticket flows to Confirmed ticket via sell once.
  7. Expiring seat hold flows to Hold expiry worker via deadline.
  8. Hold expiry worker flows to Inventory command conditional update via release if unconfirmed.

Walk the design under pressure

Model scarce inventory and reservation state explicitly

Clarify whether the system sells assigned seats, interchangeable capacity, timed entry, or a waitlist. A seat map needs per-seat state, while general admission may use a bounded count. In either model, distinguish available, held, sold, released, and expired states so the customer experience maps to durable evidence.

A hold is not a purchase. Give it an owner, expiry, and stable ID. It should reserve inventory through an authoritative transaction or concurrency mechanism rather than relying on a cache value that several buyers can read simultaneously.

Prevent oversell at the inventory boundary

For assigned seats, a conditional update or transactional lock can change a seat from available to held only if its version and state still match. For a quantity, an atomic decrement guarded by remaining capacity can reserve one unit. The exact primitive depends on the data store, but the invariant is the same: only one successful state transition consumes the last unit.

Avoid holding a long transaction open during user payment entry. Record the short inventory hold, then process payment independently with a deadline. This reduces lock contention while keeping the final confirmation tied to authoritative inventory state.

Resolve the race between payment and hold expiry

A payment can be accepted just as a hold expires. Define a deterministic policy: extend the hold while an authorized payment is in flight, attempt final confirmation before expiry, or place the order in reconciliation if evidence is uncertain. Never simply charge first and hope inventory remains.

Expiration must be processed safely even if a worker runs late. Treat it as a state transition with version checks, and make a confirmed order immune to a stale expiry worker. Audit every transition so disputes can be investigated from facts.

Staff-level insight: fairness and surge controls are product requirements

At staff scope, traffic spikes during an on-sale event need queueing, admission control, bot mitigation, tenant/event isolation, and transparent user feedback. A virtual waiting room can protect the booking system, but it must have a fairness policy and should not become an opaque bypass mechanism.

In an interview, describe the failure path: inventory service unavailable, payment pending, client retry, and final reconciliation. The strongest answers preserve the invariant, communicate uncertainty honestly, and avoid claiming a distributed workflow is magically atomic.

Keep this with you

Key takeaways

  • Scarce inventory needs authoritative conditional state transitions to prevent oversell.
  • Holds, payment attempts, and confirmed tickets are separate records with separate lifecycles.
  • Expiry, retries, fairness, and reconciliation are central to a credible booking design.

Practice aloud

Interview questions to explore

  1. 1.How do two buyers trying to reserve the last seat converge on one result?
  2. 2.What happens if payment is accepted after a hold technically expired?
  3. 3.How do you protect the system during an on-sale traffic surge?

Common follow-ups

Frequently asked questions

Why not reserve a seat only after payment succeeds?

Payment itself can be slow or uncertain. A short, durable hold gives the buyer a fair window while preserving a clear inventory boundary; the final booking still requires authoritative confirmation.

Can a cache manage ticket availability?

A cache can speed seat-map reads, but it should not be the only authority for a scarce-item state transition because stale or concurrent values can cause overselling.

Already an Elite member? Open the complete walkthrough.

Need the broader preparation context? Go back to Interview Preparation for behavioral readiness, question practice, and the larger AceTheOffer preparation framework.

Keep exploring

Back to the System Design guideBack to Interview Preparation

Keep building momentum

Popular Career Resources