Low Level Design: Sports Betting Platform

A sports betting platform is one of the harder LLD problems because it combines real-time odds management, strict financial controls, and the need to suspend markets instantly when game state changes. This design walks through the core components.

Event and Market Schema

An event is a sports match or competition. A market is a specific thing you can bet on within that event. An outcome is one of the possible results in a market:

events(event_id, sport, home_team, away_team, start_time, status)
status: ENUM('upcoming','live','completed','cancelled')

markets(market_id, event_id, market_type, status)
market_type: ENUM('match_winner','total_goals','handicap','both_teams_score')
status: ENUM('open','suspended','settled')

outcomes(outcome_id, market_id, label, decimal_odds, status)
status: ENUM('open','suspended','won','lost','void')

Odds Calculation and Bookmaker Margin

Decimal odds express the total payout per unit staked including the stake itself. An outcome with 40% implied probability has fair odds of 1/0.40 = 2.50. The bookmaker adds margin (the overround) by shading all probabilities upward so they sum to more than 100%:

implied_prob_with_margin = true_prob * (1 + margin)
decimal_odds = 1 / implied_prob_with_margin

Example (5% margin, 50/50 match):
implied_prob = 0.50 * 1.05 = 0.5238
decimal_odds = 1 / 0.5238 = 1.909 (not 2.00)

Odds are updated by the trading team or an automated feed. Every odds update is versioned — bets are accepted at the odds valid at the moment of placement, not at settlement time.

Bet Placement Schema

bets(bet_id, user_id, outcome_id, stake, decimal_odds_at_placement,
     potential_payout, status, placed_at)
status: ENUM('pending','won','lost','void','cancelled')

potential_payout = stake * decimal_odds_at_placement. This is calculated and stored at placement time. The wallet deducts the stake immediately; potential payout is credited only on settlement.

Liability Management

Liability is the maximum the bookmaker must pay out on a given outcome. It is tracked in real time:

liability(outcome_id) = SUM(potential_payout) for all pending bets on that outcome

When liability on an outcome exceeds a configured threshold, the market is automatically suspended: outcomes.status = suspended. No new bets are accepted. The trading team can then reprice the odds, reduce the threshold, or reopen manually. This prevents the book from taking catastrophic one-sided exposure.

Wallet Integration

Wallet operations must be atomic with bet placement. The flow:

  1. Check user balance >= stake.
  2. Deduct stake from wallet (optimistic lock on wallet row to prevent race conditions).
  3. Insert bet record with status pending.
  4. If bet insertion fails, reverse the wallet deduction in the same transaction.

Use a wallet ledger table (append-only) rather than a mutable balance field. The current balance is derived from SUM of ledger entries. This makes auditing trivial and prevents balance corruption from concurrent updates.

In-Play Betting and Suspension

In-play (live) betting requires suspending markets instantly when a significant event occurs — goal scored, red card, injury. The suspension flow:

  • Goal detected via data feed → publish suspension event to message queue.
  • Market service consumes event → sets markets.status = suspended within milliseconds.
  • Any bets received during the suspension window are rejected at the API layer.
  • After odds are updated, market is reopened.

Settlement

Settlement runs after the event result is confirmed. A settlement job processes all pending bets for the event:

  • Winning bets: credit potential_payout to user wallet, set status won.
  • Losing bets: set status lost, no wallet action (stake already deducted).
  • Void bets: refund stake to wallet, set status void.

Responsible Gambling Controls

Responsible gambling features are first-class requirements, not afterthoughts:

rg_limits(user_id, limit_type, amount, period, effective_from)
limit_type: ENUM('deposit','loss','stake','session_time')

self_exclusions(user_id, excluded_until, reason)

Deposit limits are enforced at the wallet layer before any deposit is processed. Self-exclusion blocks login entirely and voids any pending bets. Session time limits trigger a mandatory logout after the configured duration regardless of activity. Limit reductions take effect immediately; limit increases require a 24-hour cooling-off period by regulation in most jurisdictions.

{ “@context”: “https://schema.org”, “@type”: “FAQPage”, “mainEntity”: [ { “@type”: “Question”, “name”: “How does a second-price odds auction work in a sports betting platform?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “In a second-price (Vickrey-style) odds auction used by exchanges, multiple liquidity providers submit limit orders at their desired odds. The platform matches a bettor’s request against the order book: the bettor receives the best available odds, but the provider who is filled earns the second-best price in the book. This incentivizes providers to quote their true fair-value odds rather than gaming the system. The matching engine sorts the order book by odds descending for back bets and ascending for lay bets, then fills greedily until the requested stake is covered.” } }, { “@type”: “Question”, “name”: “How is liability management implemented in a sports betting system?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “The risk engine maintains a per-market liability ledger that tracks maximum potential payout across all accepted bets for every outcome. When a new bet is placed, the engine calculates the incremental liability (stake * (odds – 1)) and checks it against configurable exposure limits per outcome and per market. If the limit would be breached, the bet is either rejected or the odds are adjusted downward to deter further action on that outcome. Large individual bets trigger a manual review queue. Liability is recalculated in real time using an in-memory store (e.g., Redis sorted sets) to keep latency under 10 ms.” } }, { “@type”: “Question”, “name”: “How are in-play markets suspended rapidly when a key event occurs during a live match?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “The trading platform subscribes to a real-time data feed (e.g., via WebSocket from a data provider). When a significant event is detected — goal, red card, injury — the feed emits a suspension signal. The risk engine immediately sets the market status to SUSPENDED in Redis with an atomic SET command, which the betting API reads before accepting any new bet. The entire path from event detection to market suspension targets under 200 ms. Automated rules define which event types trigger suspension; a trading desk can also trigger it manually via an admin API. Markets reopen only after odds are recalculated and manually or automatically approved.” } }, { “@type”: “Question”, “name”: “What algorithm is used to calculate odds in a sports betting platform?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “Odds are derived from a probability model built from historical match data, team statistics, and real-time signals (lineup changes, weather). The raw probabilities for all outcomes must sum to 1.0. An overround (margin) is then applied: each probability is divided by (1 + margin), converting true probability to book probability. Decimal odds for each outcome are computed as 1 / book_probability. In-play odds are updated continuously using a Bayesian update step that conditions on the current match state (score, minute, possession) fed from the live data stream. The trading engine re-prices all affected markets atomically after each update cycle.” } }, { “@type”: “Question”, “name”: “How is bet settlement handled after a sports event concludes?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “When the official result is confirmed by the data feed, the settlement service queries all OPEN bets for the market. For each bet, it compares the selected outcome against the result: winning bets receive payout = stake * decimal_odds, losing bets are marked settled with payout = 0, and void bets (e.g., abandoned match) return the stake. Settlement is processed in batches using idempotent database transactions keyed on (bet_id, settlement_run_id) to prevent double-payouts on retries. Once a batch is committed, the wallet service credits or debits user balances, and push notifications are dispatched. A reconciliation job cross-checks total liabilities settled against the market’s original ledger to catch discrepancies.” } } ] }

Frequently Asked Questions

Q: How does a second-price odds auction work in a sports betting platform?

A: In a second-price (Vickrey-style) odds auction used by exchanges, multiple liquidity providers submit limit orders at their desired odds. The platform matches a bettor’s request against the order book: the bettor receives the best available odds, but the provider who is filled earns the second-best price in the book. This incentivizes providers to quote their true fair-value odds rather than gaming the system. The matching engine sorts the order book by odds descending for back bets and ascending for lay bets, then fills greedily until the requested stake is covered.

Q: How is liability management implemented in a sports betting system?

A: The risk engine maintains a per-market liability ledger that tracks maximum potential payout across all accepted bets for every outcome. When a new bet is placed, the engine calculates the incremental liability (stake * (odds – 1)) and checks it against configurable exposure limits per outcome and per market. If the limit would be breached, the bet is either rejected or the odds are adjusted downward to deter further action on that outcome. Large individual bets trigger a manual review queue. Liability is recalculated in real time using an in-memory store (e.g., Redis sorted sets) to keep latency under 10 ms.

Q: How are in-play markets suspended rapidly when a key event occurs during a live match?

A: The trading platform subscribes to a real-time data feed (e.g., via WebSocket from a data provider). When a significant event is detected — goal, red card, injury — the feed emits a suspension signal. The risk engine immediately sets the market status to SUSPENDED in Redis with an atomic SET command, which the betting API reads before accepting any new bet. The entire path from event detection to market suspension targets under 200 ms. Automated rules define which event types trigger suspension; a trading desk can also trigger it manually via an admin API. Markets reopen only after odds are recalculated and manually or automatically approved.

Q: What algorithm is used to calculate odds in a sports betting platform?

A: Odds are derived from a probability model built from historical match data, team statistics, and real-time signals (lineup changes, weather). The raw probabilities for all outcomes must sum to 1.0. An overround (margin) is then applied: each probability is divided by (1 + margin), converting true probability to book probability. Decimal odds for each outcome are computed as 1 / book_probability. In-play odds are updated continuously using a Bayesian update step that conditions on the current match state (score, minute, possession) fed from the live data stream. The trading engine re-prices all affected markets atomically after each update cycle.

Q: How is bet settlement handled after a sports event concludes?

A: When the official result is confirmed by the data feed, the settlement service queries all OPEN bets for the market. For each bet, it compares the selected outcome against the result: winning bets receive payout = stake * decimal_odds, losing bets are marked settled with payout = 0, and void bets (e.g., abandoned match) return the stake. Settlement is processed in batches using idempotent database transactions keyed on (bet_id, settlement_run_id) to prevent double-payouts on retries. Once a batch is committed, the wallet service credits or debits user balances, and push notifications are dispatched. A reconciliation job cross-checks total liabilities settled against the market’s original ledger to catch discrepancies.

See also: Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence

See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering

See also: Stripe Interview Guide 2026: Process, Bug Bash Round, and Payment Systems

Scroll to Top