SYSTEM_DESIGN

System Design: Two-Sided Marketplace

System design of a two-sided marketplace connecting buyers and sellers, covering trust systems, payment escrow, search ranking, and the marketplace cold-start problem.

17 min readUpdated Jan 15, 2025
system-designmarketplacetwo-sidedescrow

Requirements

Functional Requirements:

  • Sellers list products/services; buyers browse, search, and purchase
  • Trust and reputation system for both buyers and sellers
  • Payment escrow: funds held until buyer confirms delivery
  • Dispute resolution workflow with marketplace arbitration
  • Commission/fee management: marketplace takes a percentage per transaction
  • Seller onboarding with identity verification and payout setup

Non-Functional Requirements:

  • Support 500K active sellers and 10M active buyers
  • Search results must reflect new listings within 60 seconds
  • Payment processing with PCI DSS compliance
  • 99.99% availability for checkout and payment flows
  • Transaction data retention for 7 years (regulatory compliance)
  • Multi-currency support with real-time exchange rates

Scale Estimation

10M active buyers, 3M DAU. Listings: 500K sellers × 100 active listings = 50M listings. Search queries: 3M DAU × 4 searches = 12M searches/day = 139 QPS. Orders: 200K transactions/day = 2.3 TPS. Payment events: each transaction generates 3-5 payment events (authorization, capture, seller payout, platform fee) = 1M payment events/day. Page views: 3M DAU × 15 pages = 45M page views/day = 521 views/sec.

High-Level Architecture

The marketplace platform uses a microservices architecture with clear separation between buyer-facing, seller-facing, and platform services. The buyer path: CDN → API Gateway → Product Search (Elasticsearch) / Listing Detail (PostgreSQL + Redis cache) → Cart & Checkout → Payment Service (escrow model). The seller path: Seller Dashboard → Listing Management → Order Fulfillment → Payout Service.

The Payment Service implements a three-phase escrow model: (1) Buyer pays → funds are captured by the platform (Stripe Connect or similar); (2) Seller ships → buyer receives and confirms delivery (or auto-confirms after 14 days); (3) Platform releases funds to seller minus commission. The Dispute Service handles cases where the buyer claims non-delivery or item-not-as-described, freezing the escrowed funds until resolution.

The Trust Service maintains reputation scores for both parties. After each transaction, both buyer and seller rate each other. The aggregate score uses a Bayesian average (weighted by total transaction count) to avoid new sellers with one 5-star review outranking established sellers with hundreds of reviews.

Core Components

Escrow Payment Engine

The escrow engine manages the lifecycle of funds for each transaction. States: authorized → captured → held_in_escrow → released_to_seller | refunded_to_buyer | dispute_frozen. The engine uses Stripe Connect with the platform as the connected account: buyer's payment is captured into the platform's Stripe account, then transferred to the seller's connected account upon delivery confirmation. The platform fee (e.g., 15%) is deducted during the transfer. A scheduled job processes auto-releases: if the buyer doesn't confirm or dispute within 14 days, funds are automatically released. All state transitions are logged in an immutable ledger table for audit.

Search Ranking for Marketplace

Marketplace search ranking balances relevance with seller quality signals. The Elasticsearch query uses a function_score combining: BM25 text relevance (40%), seller trust score (25%), listing quality score based on photo count and description completeness (15%), price competitiveness percentile within category (10%), and recency boost with exponential decay (10%). New listings get a temporary boost for the first 48 hours to solve the cold-start visibility problem. Promoted listings (paid placement) are injected at fixed positions (every 5th result) and clearly labeled as sponsored.

Dispute Resolution Workflow

Disputes follow a structured workflow: buyer opens dispute → seller has 3 days to respond with evidence → if unresolved, marketplace arbitrator reviews → decision made within 5 business days. The Dispute Service manages this workflow as a state machine persisted in PostgreSQL. Evidence (photos, messages, tracking info) is stored in S3 with references in the dispute record. Automated resolution handles clear-cut cases: if tracking shows delivery and buyer claims non-delivery, the system auto-resolves in seller's favor. If the seller provides no response within 3 days, auto-resolves in buyer's favor.

Database Design

PostgreSQL schema: users table (user_id, email, type ENUM('buyer', 'seller', 'both'), trust_score FLOAT, total_transactions INT, created_at). listings table (listing_id, seller_id FK, title, description, price, currency, category_id, images JSONB, status, created_at). transactions table (transaction_id, listing_id FK, buyer_id FK, seller_id FK, amount, currency, platform_fee, escrow_status, created_at). disputes table (dispute_id, transaction_id FK, opened_by, reason, status ENUM('open', 'seller_response', 'arbitration', 'resolved'), resolution, resolved_at).

The ledger table stores all financial events: (ledger_id, transaction_id, event_type ENUM('capture', 'escrow_hold', 'seller_payout', 'platform_fee', 'refund'), amount, currency, stripe_transfer_id, created_at). This table is append-only and serves as the financial audit trail. A separate ClickHouse instance aggregates transaction data for marketplace analytics dashboards (GMV, take rate, seller performance).

API Design

  • POST /api/v1/listings — Create a listing; body contains title, description, price, category, images; returns listing_id
  • POST /api/v1/transactions — Initiate a purchase; body contains listing_id, payment_method; creates escrow and returns transaction_id
  • POST /api/v1/transactions/{id}/confirm-delivery — Buyer confirms delivery; triggers escrow release to seller
  • POST /api/v1/disputes — Open a dispute; body contains transaction_id, reason, evidence_urls; returns dispute_id

Scaling & Bottlenecks

The marketplace cold-start problem — attracting sellers without buyers and vice versa — is solved architecturally by making the buyer experience excellent even with limited inventory. The system seeds initial listings by onboarding anchor sellers (high-volume, trusted sellers recruited with reduced commissions). Search quality is maintained even with sparse inventory by broadening results (if exact matches are few, show related categories) and prominently featuring top-rated sellers.

Payment processing is the latency bottleneck: Stripe API calls take 500ms-2s. The system uses async payment capture: the order is confirmed immediately with a pending payment status, and a background worker processes the Stripe capture. If capture fails (insufficient funds, expired card), the order is cancelled and the listing is re-activated. This pattern keeps checkout latency under 500ms while handling payment provider latency asynchronously.

Key Trade-offs

  • Escrow over instant seller payment: Escrow protects buyers and reduces fraud, but delays seller cash flow by 14 days — mitigated by offering early payout (for a fee) to established sellers with high trust scores
  • Bayesian average for trust scores: Prevents new sellers from gaming ratings with a few fake reviews, but makes it harder for legitimate new sellers to build reputation — the 48-hour new listing boost compensates
  • 15% platform commission: Funds dispute resolution, buyer protection, and platform development, but reduces seller margins — competitive pressure from lower-fee platforms is the ongoing risk
  • Async payment capture: Keeps checkout fast but introduces a window where confirmed orders may fail payment — 2-3% of orders experience this, requiring graceful user communication

GO DEEPER

Master this topic in our 12-week cohort

Our Advanced System Design cohort covers this and 11 other deep-dive topics with live sessions, assignments, and expert feedback.