CHAPTER 23

Design Ticket Booking and Payments

Preventing double-booking, handling flash-sale spikes and getting money movement right

Source: PDF p. 61

Core PDF content
Functional requirementsNon-functional requirements and scale
- Browse events and seat maps; select seats - Hold seats for ~10 minutes during checkout - Pay securely; receive confirmation; refunds - Never sell the same seat twice- Strong consistency for inventory and payments - Flash sales: 500 k users competing for 20 k seats within minutes - Idempotent, auditable payment flow - Browsing is read-heavy (cache/CDN) while booking is write-contended
Figure 44. Ticketing: a waiting room smooths the spike; the seat inventory service owns a strongly consistent state machine; payments are idempotent. · PDF p. 61

Deep dives p. 61

1. Never sell a seat twice Treat each seat as a row with a tiny state machine and change state with an atomic conditional update; the database arbitrates races, so no application locking is needed:

UPDATE seats p. 61

SET status = 'HELD', hold_id = :hold, hold_expires_at = now() + interval '10 minutes' WHERE seat_id = :seat AND (status = 'AVAILABLE' OR (status = 'HELD' AND hold_expires_at < now())); -- rows_affected = 1 => you got the seat; 0 => someone else did, pick another

  • Confirming payment moves HELD -> SOLD only if hold_id still matches; a late payment for an expired hold triggers an automatic refund.
  • For contended hot rows use a short Redis hold (SET seat:42 hold NX EX 600) as a fast pre-filter, but keep the database as the source of truth. Shard inventory by event/section so a huge event does not become a single hot partition.

Review questions for this chapter have not been written and reviewed yet. The chapter text above is the full source content.

Try it

References

System Design & AI System Design: The Complete Guide — 2026 Edition, p. 61; figures 44.

Tip: use ← and → keys to move between chapters.