Skip to content

Data model

The SDK exposes the same entities the gateway holds in memory. Every shape below is what you read — not a wire format you parse.

SportEvent (BasketballMatch | FootballMatch | TennisMatch)
└── markets: ReadonlyMap<MarketId, Market>
└── Market (6 variants discriminated by `kind`)
└── selections: ReadonlyMap<SelectionId, Selection>
└── Selection
├── quote?: Quote (always present unless CLOB-only)
└── orderBook?: OrderBook (CLOB sources only)

A single match reported by one bookmaker.

FieldTypeNotes
idSportEventIdFormat vmid:<bookmaker>:<external_id>. The bookmaker is encoded in the id.
kind'se:basketball_match' | 'se:football_match' | 'se:tennis_match'Discriminator for the union.
sport'basketball' | 'football' | 'tennis'Computed from kind. Use this for narrowing.
bookmakerBookmakerComputed from id.
competitionCompetitionFormat comp:<sport>.<league>, e.g. comp:basketball.nba.
sportRegionstring | undefinedFree-form region tag (e.g. 'USA'). Optional.
startDateDateTime | undefinedLuxon DateTime. Optional — some bookmakers don’t expose it.
matchUrlstring | undefinedDeep link to the bookmaker’s page. Optional.
namestringComputed display name (e.g. "Lakers vs Celtics").
marketsReadonlyMap<MarketId, Market>The markets reported on this event.

Sport-specific fields appear after narrowing on sport:

  • BasketballMatch, FootballMatch: homeTeam: string, awayTeam: string
  • TennisMatch: competitor1: string, competitor2: string

Methods: getMarket(id), getSelection(id).

A betting market. The kind is a stable string, e.g. market:basketball_match.handicap. There are six variants today — see Markets.

FieldTypeNotes
idMarketIdFormat <SportEventId>:<external_market_id>.
kindMarketKindDiscriminator for the union.
selectionKind'over/under' | 'home/draw/away' | 'home/away' | 'competitor1/competitor2'Shape of the outcomes.
isSyntheticbooleanTrue when the SDK derived this market rather than the bookmaker reporting it directly.
selectionsReadonlyMap<SelectionId, Selection>The bettable outcomes.

Variant-specific fields (after narrowing on kind):

  • BasketballMoneyline: homeTeam, awayTeam, period
  • BasketballHandicap: homeTeam, awayTeam, period, handicap
  • BasketballTotal: homeTeam, awayTeam, period, scope, cut
  • BasketballPlayerPropOverUnder: playerName, propType, cut
  • FootballMoneyline: homeTeam, awayTeam
  • TennisMoneyline: competitor1, competitor2

Methods include getSelection(id), getSelectionByResult(result), calculateMargin().

A bettable outcome within a market.

FieldTypeNotes
idSelectionIdFormat <MarketId>:<external_selection_id>.
kindSelectionKindSame as the parent market’s selectionKind.
resultSelectionResultWhich outcome — one of over, under, home, draw, away, competitor1, competitor2. Constrained by kind.
quoteQuote | undefinedTop-of-book quote. Always present unless the market is CLOB-only.
orderBookOrderBook | undefinedFull limit order book — only on CLOB sources.
isAvailablebooleantrue when the selection currently has a usable quote.

Decimal-odds price at a point in time.

FieldTypeNotes
pricenumberDecimal odds (> 1.0). Implied probability = 1 / price.
sizenumber | undefinedAvailable stake at this price (when the source exposes liquidity).
timestampnumberObservation time, ms since epoch. See Time semantics.
impliedProbabilitynumberComputed 1 / price.

Full limit order book — only on CLOB sources.

FieldTypeNotes
bidsLevel[]Bid levels, sorted by price descending.
asksLevel[]Ask levels, sorted by price ascending.
timestampnumberSnapshot time, ms since epoch.
bestBidLevel | undefinedFirst element of bids.
bestAskLevel | undefinedFirst element of asks.
spreadnumber | undefinedbestAsk.price - bestBid.price.
midPricenumber | undefined(bestBid + bestAsk) / 2.

Level is { price: number, size: number }. Method: availableSizeUpTo(maxPrice) returns the cumulative size you can take without crossing the threshold.

markets and selections are ReadonlyMaps, not arrays. The gateway keys them by id internally; exposing the same shape here lets you do event.markets.get(marketId) in O(1) without rebuilding indexes. Iterate via .values() when you need a list.

Everything you receive is read-only. The SDK strips the mutation surface (with*, cloneWith*) at the type level — TypeScript will refuse to call them. Don’t try to mutate references; treat each event as a fresh snapshot of the affected entity.