Requirements & API: Airbnb (Marketplace)

What an interviewer expects you to nail down before drawing a single box.

Functional

  • Geo-search listings by location, dates, price, and amenities, returning a ranked result set.
  • Let hosts create and manage listings with availability calendars and pricing.
  • Book a date range with an idempotent request: hold during checkout, then commit or release, tracking status (pending → paid → canceled/refunded).
  • Handle 2-leg marketplace payments (charge guest, escrow, payout host) and guest↔host messaging.

Non-functional

  • No double-booking: two guests can never confirm the same listing for overlapping nights.
  • Search is read-heavy and latency-sensitive: sub-200ms p95 with complex filters.
  • Money correctness over speed in the booking path: payment + availability must be consistent.
  • Independent scaling: search (read-heavy) and listing authoring (write-heavy) grow separately.

API contract

GET /api/v1/search { location, checkin, checkout, guests, filters } → { listings[], next_cursor }
The dominant read path; served by Elasticsearch sharded by geohash.
POST /api/v1/bookings { listing_id, checkin, checkout } → { booking_id, hold_expires_at }
Places a TTL'd hold (Redis SETNX) before payment. This is the no-double-booking primitive.
POST /api/v1/bookings/{id}/confirm { payment_token } → { status }
Captures payment and commits the hold atomically; releases on failure.
POST /api/v1/listings { details, calendar, pricing } → { listing_id }
Host-side write, indexed into search asynchronously (~minutes of lag).

About Airbnb (Marketplace)

You type 'Lisbon next weekend, 2 guests' into Airbnb and within a fraction of a second you get a ranked page of places to stay. You pick one, click Book, enter your card, and the night is yours. Two-sided is the key phrase here: guests search and book, hosts list and manage, and the same system has to serve both. That is what makes it the classic marketplace interview question.

Here is the flow in plain terms. Your search hits a Search Service backed by an Elasticsearch index that is sharded by region, so it can rank millions of listings on location, price, and amenities in under 200ms. When you book, the Booking Service places a short hold on those exact dates, the Payments Service authorizes your card without yet capturing the money, and only then does the booking get committed to Postgres for good.

The one idea worth slowing down on is how two guests are stopped from booking the same nights. The Booking Service uses a Redis SETNX with a time-to-live: the first guest to grab the key gets a ten-minute hold, and the second guest is told to wait. Think of it like the last umbrella at a store counter. Whoever's hand lands on it first gets to take it to the register, and if they walk away it goes back on the shelf when the timer runs out.

The hold only reduces contention; the real guarantee lives in Postgres. The booking commits inside a transaction that a uniqueness constraint on the dates enforces, so even if two requests slipped past the hold, the database rejects the second. A same-user double-click is handled separately with an idempotency key (the reservation id), so a retried request returns the original booking instead of creating a second one. Hotels solve the same problem differently, because a hotel sells a room TYPE with many identical units rather than one unique place. There you keep a per-date inventory counter (total_inventory and total_reserved) and guard it with optimistic locking or a database CHECK constraint, and you can even allow a little overbooking, say up to 110%, on the bet that some guests cancel.

Notice the split that runs through the whole design. Postgres is the single source of truth for listings and bookings, while the search index is a derived, read-optimized copy that can lag a few minutes behind. The same booking event fans out through Kafka to email, host notifications, accounting, and the after-stay review prompt, none of which the guest waits on.

This system teaches the two-sided marketplace shape, geo-sharded search, the authorize-then-capture payment pattern, the ephemeral-hold-then-durable-commit trick for preventing double-booking, and why you keep one source of truth with many read-optimized views hanging off it.