Skip to main content
A selection is one bettable outcome — one row on a betting board. It is the unit the Passthrough API returns everywhere prices appear: in GET /odds, and in snapshot and update frames on the live stream. The sportsbook’s own format nests prices inside markets inside matchups, with outcomes referenced by id. The passthrough flattens all of that into a list of selections with names already resolved, so you do not have to reimplement the sportsbook’s labelling rules.

Fields

market_key

The key is the sportsbook’s own market identifier, passed through as an opaque string. It encodes the period and market type, and the line where one applies:
Treat market_key as opaque. Use it for equality and as a map key — do not parse it. The format is the sportsbook’s, and because this is a passthrough it can change without notice on their side.
All selections sharing a market_key share a version, status, cutoff_at, and limit, because those are properties of the market rather than the individual outcome.

An alternate line is its own market

Because the line is part of the key, s;0;s;-2.5 and s;0;s;-3.5 are two separate markets with independent versions. A line move arrives as a new market key, not as a changed line on an existing one — and the old key arrives in removed_market_keys when the sportsbook withdraws it.

market_name and period

market_name is composed as <period label> - <market label>, both taken from the sportsbook’s own label table rather than generated:
Period numbering is sport-specific and is not a simple counter — in esports, period 20 is Map 1 Round 3 and period 66 is Map 2 Round 13. Use market_name for display and period only as an identifier; do not derive one from the other. On a special, market_name is the special’s own description instead — Correct Score, (Map 2) Winning Margin — since that description already carries the full context.
The label table loads at startup. In the first moments of a cold start, before it is available, names fall back to a generic form such as Period 3 - Money Line. Names never invent a round number they cannot look up.

bet_name

How the outcome is named depends on the market type: Outcomes the sportsbook keys by participant id — which includes every special, and some money lines — are resolved to the participant’s name. If a name genuinely cannot be resolved, the fallback is the raw designation rather than an empty string.

price and decimal

price is American odds, exactly as the sportsbook publishes them. decimal is the same price converted, rounded to three decimal places, provided so you do not have to convert it yourself: decimal is a convenience derived from price. Where the two could ever disagree by rounding, price is authoritative.

status

A locked selection keeps its last known price. That is intentional — it lets you keep rendering the board through an in-play suspension instead of blanking it.

Two things lock a market

The upstream sportsbook only ever publishes the first of these, so the passthrough resolves both for you:
  • The market’s resolved status is not open — either the market’s own status, or the matchup’s period status when the market does not carry one.
  • cutoff_at has passed relative to the current server time.
The cutoff check exists because upstream does not retract a prematch market when a fixture goes in-play. Instead it mints a brand-new live matchup with a fresh future cutoff and abandons the prematch one, frozen at status: open forever with a cutoff in the past. Without the cutoff check those stale prematch quotes would look bettable indefinitely; with it, any client that trusts status alone is safe. You do not have to police stale prematch quotes yourself. Every GET /odds response and every stream frame also carries a top-level ts (epoch milliseconds) — the moment SportriX last applied a change to that match. If ts is not advancing, no new information has arrived for that match, and staleness is visible without any extra bookkeeping.
locked and removed are different states. A locked market is still in the book and may reopen at a new price. A market listed in removed_market_keys is gone and should be deleted from your state.

cutoff_at

RFC3339 UTC timestamp for when betting closes on this market, always normalised to a Z suffix (upstream spells the same instant as +00:00 on markets and Z on periods; both come out as Z here). Present on every selection, straight and special alike. If the market itself does not carry its own cutoff, the matchup’s period-level cutoff is used as a fallback so the field is always populated. Use cutoff_at to:
  • Detect stale prematch markets. A cutoff in the past is the passthrough’s signal that this market has been abandoned in favour of a live twin — the same signal that flips status to locked.
  • Show a countdown. Render the remaining time until the market closes.
  • Sort or filter markets by close time, for example to surface markets closing soonest.

limit

The maximum risk stake the sportsbook will accept on a single bet on this market, expressed as an integer in the account’s currency. Present on every selection. Limits vary widely — even within one match. For example, a response can carry a limit of 100 on first-half markets, 250 on team totals, 500 on match totals, and 1000 on match handicaps and 1X2. These values are illustrative, not fixed bands; always use the value returned for the current market. A client sizing a bet must read limit per market rather than assuming a match-wide, sport-wide, or account-wide constant. Use it to cap the stake you offer a user, gray out a stake input that exceeds it, or decide whether a market is deep enough to be worth surfacing at all.

version

The monotonic version of the market this selection came from. It is the mechanism for correct state updates:
  • Deduplicate. Ignore a selection whose version is not greater than the version you already hold for that market_key.
  • Detect staleness. A version that stops advancing while the feed is healthy means a quiet market, not a lost one.
Versions are only comparable within a single market_key. Comparing versions across markets is meaningless.
Match objects also carry a version. That is the match-level version and moves independently of any market’s. Do not compare the two.