Skip to main content

Data Hierarchy

Every price in the Vertex feed is anchored to a five-level hierarchy: Sport → Competition → Event → Market → Selection. Understanding this structure is essential for routing messages, building catalogs, and storing data on your side.

The five levels​

Sport​

The top-level category of competition, for example soccer, tennis, basketball, ice hockey, or MMA. Each sport has an id, a name, and a short code (e.g. soc, ten, mma). The full set is returned by /sports. Sport is the coarsest filter you can apply when discovering competitions and events over REST.

Competition​

A named competition within a sport, for example the English Premier League or ATP Masters 1000 Madrid. A competition carries id, sport_id, name, and country. Competitions are discovered via /competitions (filterable by sport).

Event​

A single scheduled match or contest, for example Arsenal vs Chelsea on a given date, or a specific MMA bout. An event carries id, sport_id, competition_id, start_time, status (scheduled, live, finished, cancelled), an active flag (whether it is open for trading), and its participants (each with id, name, a type of team or player, and role). Events are listed via /events and fetched individually via /events/{eventId}.

Market​

A bettable proposition on an event, for example match result, total goals over/under 2.5, or first-set winner. A market carries id, event_id, a segment (its classification, with code, name, and scope), an optional specifier (the line key for handicap/total variants, e.g. 2.5), a status (open, suspended, closed), and a live flag. A market's selections are returned with it via /events/{eventId}/markets.

Selection​

A single outcome within a market, for example "Arsenal to win", "Over 2.5 goals", or a player-prop outcome. A selection carries id, market_id, name, an optional participant_id, a line_value (the numeric line for handicap/total selections; null for moneyline), an optional result, and its Vertex price. The price is carried over REST in a prices array that holds the single Vertex entry (pricing_provider_id, price, status). Selections are the leaf nodes of the hierarchy and the unit at which prices are carried. Price updates stream over the WebSocket market channel as market_updates, where each selection's current price is nested inside its parent market.

Participants​

Teams and individual players are participants — a cross-cutting catalogue rather than a sixth level in the hierarchy. A participant carries id, sport_id, name, a type of team (e.g. Carolina Hurricanes) or player (e.g. an individual NHL player, tennis player, or fighter). The catalogue runs to tens of thousands of records, and /participants is paginated (filterable by sport; 100 records per page by default) — a single call returns one page, not the full set. Individual participants are fetched via /participants/{id}.

The same participant id is referenced elsewhere by foreign key: as the role-tagged competitors in an event's participants array, and as the participant_id on participant-scoped markets and selections — for example, a player-prop market carries the participant_id of the player the prop is about. Resolve that participant_id against GET /participants/{id} to recover the team or player name — or, if you are building a local lookup table, page through /participants with page/page_size.

Visual hierarchy​

Identifiers​

All identifiers in the feed are stable integers. There are no composite, prefixed, or slug-based IDs. Each entity has a plain integer id, and each level references its parent by a foreign-key field:

LevelID fieldReferences parent via
Sportidn/a (top level)
Competitionidsport_id
Eventidcompetition_id
Marketidevent_id
Selectionidmarket_id

For example, lineage is recoverable purely from these integer foreign keys: a selection delivered inside a market_updates message carries its market_id, and the enclosing market carries its event_id, so a single selection resolves up to its event without any composite identifier:

{
"id": 35928,
"market_id": 8842,
"price": { "pricing_provider_id": 1, "price": 2.6747, "status": "active" }
}

Line values are carried as discrete fields (line_value on the selection and specifier on the market) and are never encoded into an identifier. Alternate lines on the same market are simply distinct selections, distinguished by their line_value.

Implications for clients​

  • Subscriptions are made per channel (event or market), optionally filtered by event_ids. There is no "subscribe to a whole sport or competition" option; to follow a competition, list the relevant event_ids (discovered via REST). Omitting event_ids is a wildcard for everything your key is entitled to. See Subscriptions.
  • Storage: persist by selection_id, but index by event_id for fast lookup when an event lifecycle update arrives.
  • Reconciliation: if you receive a selection or market update and don't recognise its parent event, fetch that event's markets via REST before applying the update.