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)SportEvent
Section titled “SportEvent”A single match reported by one bookmaker.
| Field | Type | Notes |
|---|---|---|
id | SportEventId | Format 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. |
bookmaker | Bookmaker | Computed from id. |
competition | Competition | Format comp:<sport>.<league>, e.g. comp:basketball.nba. |
sportRegion | string | undefined | Free-form region tag (e.g. 'USA'). Optional. |
startDate | DateTime | undefined | Luxon DateTime. Optional — some bookmakers don’t expose it. |
matchUrl | string | undefined | Deep link to the bookmaker’s page. Optional. |
name | string | Computed display name (e.g. "Lakers vs Celtics"). |
markets | ReadonlyMap<MarketId, Market> | The markets reported on this event. |
Sport-specific fields appear after narrowing on sport:
BasketballMatch,FootballMatch:homeTeam: string,awayTeam: stringTennisMatch:competitor1: string,competitor2: string
Methods: getMarket(id), getSelection(id).
Market
Section titled “Market”A betting market. The kind is a stable string, e.g. market:basketball_match.handicap. There are six variants today — see Markets.
| Field | Type | Notes |
|---|---|---|
id | MarketId | Format <SportEventId>:<external_market_id>. |
kind | MarketKind | Discriminator for the union. |
selectionKind | 'over/under' | 'home/draw/away' | 'home/away' | 'competitor1/competitor2' | Shape of the outcomes. |
isSynthetic | boolean | True when the SDK derived this market rather than the bookmaker reporting it directly. |
selections | ReadonlyMap<SelectionId, Selection> | The bettable outcomes. |
Variant-specific fields (after narrowing on kind):
BasketballMoneyline:homeTeam,awayTeam,periodBasketballHandicap:homeTeam,awayTeam,period,handicapBasketballTotal:homeTeam,awayTeam,period,scope,cutBasketballPlayerPropOverUnder:playerName,propType,cutFootballMoneyline:homeTeam,awayTeamTennisMoneyline:competitor1,competitor2
Methods include getSelection(id), getSelectionByResult(result), calculateMargin().
Selection
Section titled “Selection”A bettable outcome within a market.
| Field | Type | Notes |
|---|---|---|
id | SelectionId | Format <MarketId>:<external_selection_id>. |
kind | SelectionKind | Same as the parent market’s selectionKind. |
result | SelectionResult | Which outcome — one of over, under, home, draw, away, competitor1, competitor2. Constrained by kind. |
quote | Quote | undefined | Top-of-book quote. Always present unless the market is CLOB-only. |
orderBook | OrderBook | undefined | Full limit order book — only on CLOB sources. |
isAvailable | boolean | true when the selection currently has a usable quote. |
Decimal-odds price at a point in time.
| Field | Type | Notes |
|---|---|---|
price | number | Decimal odds (> 1.0). Implied probability = 1 / price. |
size | number | undefined | Available stake at this price (when the source exposes liquidity). |
timestamp | number | Observation time, ms since epoch. See Time semantics. |
impliedProbability | number | Computed 1 / price. |
OrderBook
Section titled “OrderBook”Full limit order book — only on CLOB sources.
| Field | Type | Notes |
|---|---|---|
bids | Level[] | Bid levels, sorted by price descending. |
asks | Level[] | Ask levels, sorted by price ascending. |
timestamp | number | Snapshot time, ms since epoch. |
bestBid | Level | undefined | First element of bids. |
bestAsk | Level | undefined | First element of asks. |
spread | number | undefined | bestAsk.price - bestBid.price. |
midPrice | number | undefined | (bestBid + bestAsk) / 2. |
Level is { price: number, size: number }. Method: availableSizeUpTo(maxPrice) returns the cumulative size you can take without crossing the threshold.
Why Maps and not arrays?
Section titled “Why Maps and not arrays?”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.
Read-only
Section titled “Read-only”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.