diff --git a/content/en/api-reference/leagues.mdx b/content/en/api-reference/leagues.mdx index 1652f7b..397af25 100644 --- a/content/en/api-reference/leagues.mdx +++ b/content/en/api-reference/leagues.mdx @@ -75,6 +75,7 @@ for league in result['data']: "data": [ { "id": "nba", + "numerical_id": 87, "name": "NBA", "sport": "basketball", "event_count": 15, @@ -82,6 +83,7 @@ for league in result['data']: }, { "id": "ncaab", + "numerical_id": 88, "name": "NCAAB", "sport": "basketball", "event_count": 27, @@ -89,6 +91,7 @@ for league in result['data']: }, { "id": "wnba", + "numerical_id": 89, "name": "WNBA", "sport": "basketball", "event_count": 0, @@ -250,11 +253,22 @@ for league in result['data']: | Field | Type | Description | |-------|------|-------------| | `id` | string | League identifier (lowercase, use in API filters) | +| `numerical_id` | integer \| null | Stable integer key for the league (frozen, never reused). New (May 2026) — additive, optional. See [Entity reference IDs](/en/concepts/entity-reference-ids). | | `name` | string | Human-readable league name | | `sport` | string | Parent sport ID | | `event_count` | integer | Total events currently available with odds | | `live_count` | integer | Events currently live/in-play | +### New (May 2026): `numerical_id` + +`numerical_id` is a frozen, dense-from-1 integer assigned per league in the SharpAPI atlas. The full registry currently spans ~1,000 leagues across all 19 sports. Use it as a compact join/index key when storing rows in your own database. + +- **Frozen:** never reused or remapped. +- **Optional:** absent (or `null`) for leagues that haven't been mapped yet — slug `id` is always present. +- **Domain-scoped:** unique across leagues only. + +Every odds row and opportunity leg also carries a matching `league_ref` block (`{id, label, numerical_id}`) so you don't need to second-fetch this endpoint just to label a row. See [Entity reference IDs](/en/concepts/entity-reference-ids) for the full contract. + ## Common Leagues The endpoint is the canonical source of truth — call `GET /api/v1/leagues` for the complete, up-to-date list. The atlas registry catalogs **600+ leagues across 30+ sports** including UEFA continental competitions, multiple basketball circuits per country, and full tennis/golf/MMA/esports/cricket coverage. The illustrative subset below shows the highest-volume entries you'll typically filter on: diff --git a/content/en/api-reference/markets.mdx b/content/en/api-reference/markets.mdx index 33b5970..cff0735 100644 --- a/content/en/api-reference/markets.mdx +++ b/content/en/api-reference/markets.mdx @@ -80,6 +80,7 @@ for market in result['data']: "data": [ { "id": "moneyline", + "numerical_id": 878, "name": "Moneyline", "description": "Bet on which team will win the game outright", "hasLine": false, @@ -90,6 +91,7 @@ for market in result['data']: }, { "id": "point_spread", + "numerical_id": 880, "name": "Point Spread", "description": "Bet on the point margin between teams", "hasLine": true, @@ -100,6 +102,7 @@ for market in result['data']: }, { "id": "total_points", + "numerical_id": 881, "name": "Total Points", "description": "Bet on the combined score of both teams (over/under)", "hasLine": true, @@ -187,6 +190,7 @@ for market in result['data']: | Field | Type | Description | |-------|------|-------------| | `id` | string | Unique market identifier (use in API filters) | +| `numerical_id` | integer \| null | Stable integer key for the market type (frozen, never reused). New (May 2026) — additive, optional. See [Entity reference IDs](/en/concepts/entity-reference-ids). | | `name` | string | Human-readable market name | | `description` | string | Brief description of the market | | `hasLine` | boolean | Whether this market includes a line value | @@ -195,6 +199,16 @@ for market in result['data']: | `selection_count` | number \| null | Number of unique selections across all events | | `sports` | string[] | Sport IDs that currently have this market | +### New (May 2026): `numerical_id` + +`numerical_id` is a frozen, dense-from-1 integer assigned per market type in the SharpAPI atlas. The market catalog covers ~3,000 canonical types (core lines + period markets + player props across all sports). + +- **Frozen:** never reused or remapped. +- **Optional:** absent (or `null`) for niche markets that haven't been assigned an integer yet — slug `id` is always present. +- **Domain-scoped:** unique across markets only. + +Every odds row and opportunity leg also carries a matching `market_ref` block (`{id, label, numerical_id}`). See [Entity reference IDs](/en/concepts/entity-reference-ids). + ## Market Types ### Core Markets diff --git a/content/en/api-reference/odds.mdx b/content/en/api-reference/odds.mdx index 94fb981..a845857 100644 --- a/content/en/api-reference/odds.mdx +++ b/content/en/api-reference/odds.mdx @@ -175,6 +175,8 @@ Cursors are opaque — do not parse or construct them. They encode the sort posi ### Success (200) +The example below shows the flat fields only. As of May 2026, every row also carries optional nested reference blocks (`home`, `away`, `sport_ref`, `league_ref`, `market_ref`, `sportsbook_ref`) — see [Nested reference blocks](#new-may-2026-nested-reference-blocks) below. + ```json { "success": true, @@ -319,6 +321,41 @@ X-Request-Id: req_abc123def456 | `stat_category` | string\|undefined | Stat category, e.g. `points`, `rebounds` (player prop markets only) | | `public_bet_pct` | number\|undefined | Public betting ticket percentage (0.0-1.0). Currently BetMGM only. | | `max_bet` | number\|undefined | Maximum wager amount (USD) for this market type. Currently Pinnacle only. | +| `home` | object\|undefined | **New (May 2026).** Nested home-team reference: `{id, numerical_id, name, abbreviation}`. See [Entity reference IDs](/en/concepts/entity-reference-ids). | +| `away` | object\|undefined | **New (May 2026).** Nested away-team reference: `{id, numerical_id, name, abbreviation}`. | +| `sport_ref` | object\|undefined | **New (May 2026).** Nested sport reference: `{id, numerical_id, name}`. | +| `league_ref` | object\|undefined | **New (May 2026).** Nested league reference: `{id, numerical_id, label}`. | +| `market_ref` | object\|undefined | **New (May 2026).** Nested market reference: `{id, numerical_id, label}`. | +| `sportsbook_ref` | object\|undefined | **New (May 2026).** Nested sportsbook reference: `{id, numerical_id, label}`. | + +### New (May 2026): nested reference blocks + +Every odds row now carries six optional **nested reference objects** that bundle each entity's slug `id`, display label, and stable `numerical_id` directly with the row. The flat string fields (`sport`, `league`, `home_team`, `away_team`, `market_type`, `sportsbook`) remain unchanged — the new blocks are purely additive. + +```json +{ + "id": "pinnacle_mlb_yankees_redsox_moneyline_NYY", + "sportsbook": "pinnacle", + "sport": "baseball", + "league": "mlb", + "home_team": "New York Yankees", + "away_team": "Boston Red Sox", + "market_type": "moneyline", + "selection": "New York Yankees", + "odds_american": -135, + + "home": { "id": "new_york_yankees", "numerical_id": 20, "name": "New York Yankees", "abbreviation": "NYY" }, + "away": { "id": "boston_red_sox", "numerical_id": 5, "name": "Boston Red Sox", "abbreviation": "BOS" }, + "sport_ref": { "id": "baseball", "numerical_id": 3, "name": "Baseball" }, + "league_ref": { "id": "mlb", "numerical_id": 354, "label": "MLB" }, + "market_ref": { "id": "moneyline","numerical_id": 878, "label": "Moneyline" }, + "sportsbook_ref": { "id": "pinnacle", "numerical_id": 28, "label": "Pinnacle" } +} +``` + +**When fields are absent.** Each block is emitted only when the underlying entity is mapped in the SharpAPI atlas. Unmapped entities (long-tail leagues, niche markets, fresh sportsbook additions) omit the block, in which case the flat field on the row is the only ID you'll see. Treat every block — and every inner field, including `numerical_id` and `abbreviation` — as optional. + +See [Entity reference IDs](/en/concepts/entity-reference-ids) for the full semantics, the dense-from-1 / frozen / never-reused contract, and recommended use cases (storage keys, cross-feed mapping, display labels). ## Sorting diff --git a/content/en/api-reference/opportunities-arbitrage.mdx b/content/en/api-reference/opportunities-arbitrage.mdx index 728261f..4dd9754 100644 --- a/content/en/api-reference/opportunities-arbitrage.mdx +++ b/content/en/api-reference/opportunities-arbitrage.mdx @@ -262,6 +262,37 @@ X-Request-Id: req_arb789xyz012 | `external_event_id` | string\|null | Sportsbook's native event ID | | `selection_id` | string\|null | Sportsbook's selection/outcome ID | | `market_id` | string\|null | Sportsbook's market ID | +| `home` | object\|undefined | **New (May 2026).** Nested home-team reference: `{id, numerical_id, name, abbreviation}`. See [Entity reference IDs](/en/concepts/entity-reference-ids). | +| `away` | object\|undefined | **New (May 2026).** Nested away-team reference: `{id, numerical_id, name, abbreviation}`. | +| `sport_ref` | object\|undefined | **New (May 2026).** Nested sport reference: `{id, numerical_id, name}`. | +| `league_ref` | object\|undefined | **New (May 2026).** Nested league reference: `{id, numerical_id, label}`. | +| `market_ref` | object\|undefined | **New (May 2026).** Nested market reference: `{id, numerical_id, label}`. | +| `sportsbook_ref` | object\|undefined | **New (May 2026).** Nested sportsbook reference for this leg's book: `{id, numerical_id, label}`. | + +### New (May 2026): nested reference blocks on each leg + +Every arbitrage leg now carries six optional nested reference objects, mirroring the shape on `/odds` and `/ev`. The flat top-level fields (`sport`, `league`, `home_team`, `away_team`, `market_type`) and per-leg `sportsbook` / `selection` strings are unchanged — the new blocks are purely additive. + +```json +{ + "legs": [ + { + "sportsbook": "draftkings", + "selection": "Los Angeles Lakers", + "odds_american": 145, + + "home": { "id": "los_angeles_lakers", "numerical_id": 14, "name": "Los Angeles Lakers", "abbreviation": "LAL" }, + "away": { "id": "boston_celtics", "numerical_id": 3, "name": "Boston Celtics", "abbreviation": "BOS" }, + "sport_ref": { "id": "basketball", "numerical_id": 1, "name": "Basketball" }, + "league_ref": { "id": "nba", "numerical_id": 87, "label": "NBA" }, + "market_ref": { "id": "moneyline", "numerical_id": 878, "label": "Moneyline" }, + "sportsbook_ref": { "id": "draftkings", "numerical_id": 12, "label": "DraftKings" } + } + ] +} +``` + +Each block is emitted only when the underlying entity is mapped in the atlas; treat every block (and every inner field) as **optional**. The two competitor blocks (`home`, `away`) are identical across all legs of the same opportunity — the leg differs only in `sportsbook_ref`, `selection`, and the price. See [Entity reference IDs](/en/concepts/entity-reference-ids) for the full contract. ### CSV Format diff --git a/content/en/api-reference/opportunities-ev.mdx b/content/en/api-reference/opportunities-ev.mdx index 68dec7a..3fad748 100644 --- a/content/en/api-reference/opportunities-ev.mdx +++ b/content/en/api-reference/opportunities-ev.mdx @@ -317,6 +317,36 @@ X-Request-Id: req_abc123def456 | `oldest_odds_age_seconds` | number\|null | Age of the stalest odds used in the EV calculation (seconds) | | `warnings` | string[] | Data quality warnings (e.g., `POTENTIALLY_STALE_ODDS`, `LIVE_STALE_ODDS`) | | `detected_at` | string | ISO 8601 timestamp when the +EV was first detected | +| `home` | object\|undefined | **New (May 2026).** Nested home-team reference: `{id, numerical_id, name, abbreviation}`. See [Entity reference IDs](/en/concepts/entity-reference-ids). | +| `away` | object\|undefined | **New (May 2026).** Nested away-team reference: `{id, numerical_id, name, abbreviation}`. | +| `sport_ref` | object\|undefined | **New (May 2026).** Nested sport reference: `{id, numerical_id, name}`. | +| `league_ref` | object\|undefined | **New (May 2026).** Nested league reference: `{id, numerical_id, label}`. | +| `market_ref` | object\|undefined | **New (May 2026).** Nested market reference: `{id, numerical_id, label}`. | +| `sportsbook_ref` | object\|undefined | **New (May 2026).** Nested sportsbook reference: `{id, numerical_id, label}`. | + +### New (May 2026): nested reference blocks + +Every +EV row now carries six optional nested reference objects that bundle each entity's slug `id`, display label, and stable `numerical_id` alongside the row's flat fields. They are emitted by the in-process EV engine and are also present on `/api/v1/stream/opportunities` SSE frames. + +```json +{ + "id": "ev_pinnacle_mlb_yankees_redsox_moneyline_NYY", + "sportsbook": "draftkings", + "sport": "baseball", + "league": "mlb", + "market": "moneyline", + "ev_percentage": 4.2, + + "home": { "id": "new_york_yankees", "numerical_id": 20, "name": "New York Yankees", "abbreviation": "NYY" }, + "away": { "id": "boston_red_sox", "numerical_id": 5, "name": "Boston Red Sox", "abbreviation": "BOS" }, + "sport_ref": { "id": "baseball", "numerical_id": 3, "name": "Baseball" }, + "league_ref": { "id": "mlb", "numerical_id": 354, "label": "MLB" }, + "market_ref": { "id": "moneyline","numerical_id": 878, "label": "Moneyline" }, + "sportsbook_ref": { "id": "pinnacle", "numerical_id": 28, "label": "Pinnacle" } +} +``` + +Each block is emitted only when the underlying entity is mapped in the SharpAPI atlas — treat every block (and every inner field) as **optional**. See [Entity reference IDs](/en/concepts/entity-reference-ids) for the full contract, the dense-from-1 / frozen / never-reused guarantees, and recommended use. ### Meta Summary Fields diff --git a/content/en/api-reference/opportunities-middles.mdx b/content/en/api-reference/opportunities-middles.mdx index 858f7f0..780f47a 100644 --- a/content/en/api-reference/opportunities-middles.mdx +++ b/content/en/api-reference/opportunities-middles.mdx @@ -245,6 +245,36 @@ X-Request-Id: req_mid456abc789 | `stake_percent` | number | Recommended stake allocation (% of total) | | `odds_age_seconds` | number\|null | Age of this side's odds at detection time | | `deep_link` | string\|null | Direct link to place this bet at the sportsbook | +| `home` | object\|undefined | **New (May 2026).** Nested home-team reference: `{id, numerical_id, name, abbreviation}`. See [Entity reference IDs](/en/concepts/entity-reference-ids). | +| `away` | object\|undefined | **New (May 2026).** Nested away-team reference: `{id, numerical_id, name, abbreviation}`. | +| `sport_ref` | object\|undefined | **New (May 2026).** Nested sport reference: `{id, numerical_id, name}`. | +| `league_ref` | object\|undefined | **New (May 2026).** Nested league reference: `{id, numerical_id, label}`. | +| `market_ref` | object\|undefined | **New (May 2026).** Nested market reference: `{id, numerical_id, label}`. | +| `sportsbook_ref` | object\|undefined | **New (May 2026).** Nested sportsbook reference for this side's book: `{id, numerical_id, label}`. | + +### New (May 2026): nested reference blocks on each side + +`side1` and `side2` each gain six optional nested reference objects, mirroring the shape on `/odds`, `/ev`, and `/arbitrage`. The flat top-level fields (`sport`, `league`, `home_team`, `away_team`, `market_type`) and per-side `book` / `selection` strings are unchanged — the new blocks are purely additive. + +```json +{ + "side1": { + "book": "draftkings", + "selection": "Kansas City Chiefs", + "line": -2.5, + "odds": { "american": -110, "decimal": 1.909, "probability": 0.524, "fair_probability": 0.524 }, + + "home": { "id": "kansas_city_chiefs", "numerical_id": 11, "name": "Kansas City Chiefs", "abbreviation": "KC" }, + "away": { "id": "buffalo_bills", "numerical_id": 4, "name": "Buffalo Bills", "abbreviation": "BUF" }, + "sport_ref": { "id": "football", "numerical_id": 2, "name": "Football" }, + "league_ref": { "id": "nfl", "numerical_id": 90, "label": "NFL" }, + "market_ref": { "id": "point_spread","numerical_id": 880, "label": "Point Spread" }, + "sportsbook_ref": { "id": "draftkings", "numerical_id": 12, "label": "DraftKings" } + } +} +``` + +Each block is emitted only when the underlying entity is mapped in the atlas; treat every block (and every inner field) as **optional**. The two competitor blocks (`home`, `away`) are identical across both sides of the same middle — the sides differ only in `sportsbook_ref`, `selection`, `line`, and the price. See [Entity reference IDs](/en/concepts/entity-reference-ids) for the full contract. ### Warning Flags diff --git a/content/en/api-reference/sports.mdx b/content/en/api-reference/sports.mdx index f26cb73..1283ea6 100644 --- a/content/en/api-reference/sports.mdx +++ b/content/en/api-reference/sports.mdx @@ -66,6 +66,7 @@ for sport in result['data']: "data": [ { "id": "basketball", + "numerical_id": 1, "name": "Basketball", "leagues": ["nba", "ncaab", "wnba"], "event_count": 42, @@ -73,6 +74,7 @@ for sport in result['data']: }, { "id": "football", + "numerical_id": 2, "name": "Football", "leagues": ["nfl", "ncaaf"], "event_count": 28, @@ -80,6 +82,7 @@ for sport in result['data']: }, { "id": "hockey", + "numerical_id": 4, "name": "Hockey", "leagues": ["nhl"], "event_count": 15, @@ -87,6 +90,7 @@ for sport in result['data']: }, { "id": "baseball", + "numerical_id": 3, "name": "Baseball", "leagues": ["mlb"], "event_count": 0, @@ -141,11 +145,22 @@ for sport in result['data']: | Field | Type | Description | |-------|------|-------------| | `id` | string | Sport identifier (lowercase, use in API filters) | +| `numerical_id` | integer \| null | Stable integer key for the sport (frozen, never reused). New (May 2026) — additive, optional. See [Entity reference IDs](/en/concepts/entity-reference-ids). | | `name` | string | Human-readable sport name | | `leagues` | string[] | League IDs within this sport | | `event_count` | integer | Total events currently available with odds | | `live_count` | integer | Events currently live/in-play | +### New (May 2026): `numerical_id` + +`numerical_id` is a frozen, dense-from-1 integer assigned per sport in the SharpAPI atlas. Use it as a compact storage key when you don't need the human-readable slug. + +- **Frozen:** never reused or remapped once assigned. +- **Optional:** absent (or `null`) for sports that haven't been mapped yet — the slug `id` is always present. +- **Domain-scoped:** unique across sports only; pair with the entity domain to disambiguate. + +See [Entity reference IDs](/en/concepts/entity-reference-ids) for the full semantics, plus the matching `sport_ref` block emitted on every odds row and opportunity leg. + ## Available Sports | ID | Display Name | Popular Leagues | diff --git a/content/en/api-reference/sportsbooks.mdx b/content/en/api-reference/sportsbooks.mdx index af46936..8055acc 100644 --- a/content/en/api-reference/sportsbooks.mdx +++ b/content/en/api-reference/sportsbooks.mdx @@ -70,6 +70,7 @@ for book in result['data']: "data": [ { "id": "draftkings", + "numerical_id": 12, "name": "draftkings", "display_name": "DraftKings", "has_live_odds": true, @@ -83,6 +84,7 @@ for book in result['data']: }, { "id": "fanduel", + "numerical_id": 14, "name": "fanduel", "display_name": "FanDuel", "has_live_odds": true, @@ -161,6 +163,7 @@ for book in result['data']: }, { "id": "pinnacle", + "numerical_id": 28, "name": "pinnacle", "display_name": "Pinnacle", "has_live_odds": true, @@ -310,6 +313,7 @@ for book in result['data']: | Field | Type | Description | |-------|------|-------------| | `id` | string | Unique identifier (use in API filters) | +| `numerical_id` | integer \| null | Stable integer key for the sportsbook (frozen, never reused). New (May 2026) — additive, optional. See [Entity reference IDs](/en/concepts/entity-reference-ids). | | `name` | string | Internal name (same as `id`) | | `display_name` | string | Human-readable name | | `has_live_odds` | boolean | Supports live/in-play odds | @@ -325,6 +329,16 @@ for book in result['data']: The `event_count` may be 0 and `last_update` may be `null` if a sportsbook is temporarily unavailable or experiencing data delays. +### New (May 2026): `numerical_id` + +`numerical_id` is a frozen, dense-from-1 integer assigned per sportsbook in the SharpAPI atlas. It's stable across rebrands and slug renames — `pinnacle` is `numerical_id: 28` regardless of any future display-name changes. + +- **Frozen:** never reused or remapped. +- **Optional:** absent (or `null`) for sportsbooks not yet mapped (e.g. brand-new books in the catalog before assignment); slug `id` is always present. +- **Domain-scoped:** unique across sportsbooks only. + +Every odds row and opportunity leg also carries a matching `sportsbook_ref` block (`{id, label, numerical_id}`). See [Entity reference IDs](/en/concepts/entity-reference-ids). + ## Book Access by Tier The `requires_tier` field indicates the minimum subscription tier needed to access a sportsbook's odds data through the API. diff --git a/content/en/api-reference/teams.mdx b/content/en/api-reference/teams.mdx index 789f700..09b9e45 100644 --- a/content/en/api-reference/teams.mdx +++ b/content/en/api-reference/teams.mdx @@ -91,7 +91,9 @@ for team in result['data'][:10]: "data": [ { "id": "arsenal", + "numerical_id": 1042, "name": "Arsenal", + "abbreviation": "ARS", "sport": "soccer", "leagues": [ "EPL", @@ -107,7 +109,9 @@ for team in result['data'][:10]: }, { "id": "alabama-crimson-tide", + "numerical_id": 318, "name": "Alabama Crimson Tide", + "abbreviation": "ALA", "sport": "basketball", "leagues": [ "NCAAB" @@ -138,13 +142,25 @@ for team in result['data'][:10]: | Field | Type | Description | |-------|------|-------------| | `id` | string | Unique team identifier (slug format, e.g., `alabama-crimson-tide`) | +| `numerical_id` | integer \| null | Stable integer key for the team (frozen, never reused). New (May 2026) — additive, optional. See [Entity reference IDs](/en/concepts/entity-reference-ids). | | `name` | string | Display name (e.g., `Alabama Crimson Tide`) | +| `abbreviation` | string \| null | Short code (e.g., `ALA`, `ARS`, `NYY`). New (May 2026) — populated where a broadly-recognized abbreviation exists. | | `sport` | string | Primary sport (e.g., `basketball`, `soccer`, `football`, `hockey`) | | `leagues` | array | Leagues this team appears in (e.g., `["NBA", "NCAAB"]`) | | `aliases` | array | Alternative names used by different sportsbooks (e.g., `["Alabama", "Bama"]`) | | `event_count` | integer | Number of current events involving this team | | `live_count` | integer | Number of currently live events involving this team | +### New (May 2026): `numerical_id` and `abbreviation` + +`numerical_id` is a frozen, dense-from-1 integer assigned per team in the SharpAPI atlas (~5,000+ entries across all sports). `abbreviation` is the team's short code where one is broadly known (US major leagues, EPL, ATP/WTA — `NYY`, `ARS`, `LAL`, etc.). + +- **Frozen:** `numerical_id` is never reused or remapped, even if the team renames or moves leagues. +- **Optional:** both fields are absent (or `null`) for teams that haven't been mapped or don't have a standard short code. The slug `id` and `name` are always present. +- **Domain-scoped:** `numerical_id` is unique across teams only. + +Every odds row and opportunity leg also carries `home` and `away` blocks with the same shape (`{id, numerical_id, name, abbreviation}`), so you don't need to second-fetch this endpoint just to label rows. See [Entity reference IDs](/en/concepts/entity-reference-ids) for the full contract. + ## Meta Object | Field | Type | Description | diff --git a/content/en/concepts/_meta.js b/content/en/concepts/_meta.js index 625281d..14c7909 100644 --- a/content/en/concepts/_meta.js +++ b/content/en/concepts/_meta.js @@ -3,6 +3,7 @@ export default { "ev-calculation": "EV Calculation", arbitrage: "Arbitrage", "event-matching": "Event Matching", + "entity-reference-ids": "Entity Reference IDs", "live-vs-prematch": "Live vs. Pre-Match", "pinnacle-odds-changed-at": "Pinnacle `odds_changed_at`", } diff --git a/content/en/concepts/entity-reference-ids.mdx b/content/en/concepts/entity-reference-ids.mdx new file mode 100644 index 0000000..dc19fca --- /dev/null +++ b/content/en/concepts/entity-reference-ids.mdx @@ -0,0 +1,110 @@ +--- +description: "Entity reference IDs — numerical_id semantics, nested team/sport/league/market/sportsbook objects, and how to use them for joins, indexing, and cross-feed mapping." +--- + +import { Callout } from 'nextra/components' + +# Entity reference IDs + +SharpAPI emits stable, integer-keyed identifiers (`numerical_id`) on every reference entity, plus self-describing nested reference objects on every odds row and opportunity leg. This page documents what those IDs guarantee, how to use them, and how they relate to the existing string IDs. + + + **New (May 2026).** Both `numerical_id` and the nested reference objects are **additive**. Existing string IDs (`sport: "baseball"`, `league: "mlb"`, `sportsbook: "pinnacle"`, `home_team: "New York Yankees"`) remain in every response and are not deprecated. There is no removal timeline — both shapes are supported indefinitely. + + +## What's new + +Each reference endpoint (`/sports`, `/leagues`, `/sportsbooks`, `/markets`, `/teams`) now returns a `numerical_id` integer alongside the existing slug `id`. `/teams` additionally returns an `abbreviation` field where one is known. + +Each odds row (and each leg of an EV / arbitrage / middle opportunity) now carries six optional **nested reference objects** that bundle the entity's `id`, display label, and `numerical_id` directly with the row — no second lookup against `/sports` or `/teams` needed: + +```json +{ + "home": { "id": "new_york_yankees", "numerical_id": 20, "name": "New York Yankees", "abbreviation": "NYY" }, + "away": { "id": "boston_red_sox", "numerical_id": 5, "name": "Boston Red Sox", "abbreviation": "BOS" }, + "sport_ref": { "id": "baseball", "numerical_id": 3, "name": "Baseball" }, + "league_ref": { "id": "mlb", "numerical_id": 354, "label": "MLB" }, + "market_ref": { "id": "moneyline", "numerical_id": 878, "label": "Moneyline" }, + "sportsbook_ref": { "id": "pinnacle", "numerical_id": 28, "label": "Pinnacle" } +} +``` + +## `numerical_id` semantics + +Each `numerical_id` is allocated from a frozen, per-domain registry under `api-adapters/sharp_atlas/`. The contract is: + +| Property | Guarantee | +|---|---| +| **Frozen** | Once assigned, a `numerical_id` is never reused, reissued, or remapped to a different entity. The Yankees' `numerical_id: 20` will be `20` until the API is retired. | +| **Dense from 1** | IDs start at `1` and are issued sequentially per domain. There are no negative or zero IDs and no large skips. Sports, leagues, sportsbooks, markets, and teams each have an independent dense range. | +| **Domain-scoped** | A `numerical_id` is only unique within its domain (sport, league, sportsbook, market, team). `numerical_id: 3` on a sport is unrelated to `numerical_id: 3` on a team. Pair the integer with the domain to disambiguate. | +| **Assigned, not derived** | IDs are explicitly tracked in the atlas JSONs — they are not hashes of the slug or computed from sort order. Adding a new entity allocates the next free integer; renaming a slug does not change its `numerical_id`. | +| **Not a sportsbook ID** | This is SharpAPI's identifier, not the sportsbook's internal one. A book's native event/market/selection IDs are still emitted on a per-row basis — see `external_event_id`, `selection_id`, `market_id`, and `external_ids` on the [Events](/en/api-reference/events) endpoint. | + +## When fields are absent + +The nested reference objects are emitted **only when the underlying entity has been mapped in the atlas**. For unmapped entities — typically long-tail leagues, exotic markets, or freshly added sportsbooks before catalog assignment — the corresponding `*_ref` block is omitted (or has `numerical_id: null`) and the existing string field on the row is the only ID you'll see. + +In practice: + +- Major sports, leagues, and books are fully mapped — expect every `*_ref` block to be present. +- Player-prop markets and corners/cards/period markets in soccer have the broadest catalog; some niche prop types are still being assigned. +- Team `abbreviation` is populated where one is broadly known (US major leagues, EPL, ATP/WTA short codes). For minor / international teams it may be absent. + +Consumers should treat every nested block as **optional**. Generic clients should fall back to the flat string field (`sport`, `league`, `sportsbook`, `home_team`, `away_team`, `market_type`) when the corresponding `*_ref` is not present. + +## Recommended usage + +### Indexing & joins +Use `numerical_id` as the primary key when storing odds/opportunities in your own database. Integer keys are smaller, cheaper to index, and stable across slug renames or display-label tweaks. + +### Cross-feed mapping +If you ingest from multiple data providers, `numerical_id` gives you a fast equality check inside SharpAPI rows. For mapping **across** vendors, the slug `id` (`mlb`, `pinnacle`, `new_york_yankees`) is still the more portable join key — slugs are human-readable and tend to overlap across vendors more than integer IDs do. + +### UI display +Use `name` (sports, teams) or `label` (leagues, markets, sportsbooks) for display; the `abbreviation` on `home`/`away` is appropriate for compact cells. + +### Streaming +The same nested objects appear on `/api/v1/stream/odds` SSE frames and on WebSocket v1 / v1.5 odds payloads — no separate stream is required. + +## Field reference + +### Reference endpoints + +Every reference endpoint adds `numerical_id` to its existing object schema. `/teams` additionally adds `abbreviation`. + +| Endpoint | Added field | Type | Notes | +|---|---|---|---| +| [`/sports`](/en/api-reference/sports) | `numerical_id` | integer \| null | Sport-scoped domain | +| [`/leagues`](/en/api-reference/leagues) | `numerical_id` | integer \| null | League-scoped domain | +| [`/sportsbooks`](/en/api-reference/sportsbooks) | `numerical_id` | integer \| null | Sportsbook-scoped domain | +| [`/markets`](/en/api-reference/markets) | `numerical_id` | integer \| null | Market-type-scoped domain | +| [`/teams`](/en/api-reference/teams) | `numerical_id`, `abbreviation` | integer \| null, string \| null | Team-scoped domain | + +### Nested reference blocks on odds & opportunity legs + +| Block | Where | Fields | Purpose | +|---|---|---|---| +| `home`, `away` | Every odds row, every opportunity leg | `id`, `numerical_id`, `name`, `abbreviation` | Resolve the two competitors without a separate `/teams` call. | +| `sport_ref` | Same | `id`, `numerical_id`, `name` | Display-ready sport reference. | +| `league_ref` | Same | `id`, `numerical_id`, `label` | Display-ready league reference. | +| `market_ref` | Same | `id`, `numerical_id`, `label` | Display-ready market reference (canonical market type). | +| `sportsbook_ref` | Same | `id`, `numerical_id`, `label` | Display-ready sportsbook reference. | + +All inner fields are **optional** within a block. A block may be present with a `null` `numerical_id` if the slug has been mapped but the integer assignment is pending; both `numerical_id` and the entire block may also be absent for unmapped entities. + +## Migration + +There is nothing to migrate. Continue using the flat string fields if they cover your needs. Adopt the `*_ref` blocks and `numerical_id` selectively when: + +- you need a stable integer key for storage, +- you want display-ready labels without a second API call, +- or you're building a cross-feed normalization layer. + +The flat fields and the nested blocks describe the same row — they will not contradict each other. + +## Related + +- [Sports](/en/api-reference/sports), [Leagues](/en/api-reference/leagues), [Sportsbooks](/en/api-reference/sportsbooks), [Markets](/en/api-reference/markets), [Teams](/en/api-reference/teams) — reference endpoints with the new `numerical_id` field +- [Odds Snapshot](/en/api-reference/odds), [+EV Opportunities](/en/api-reference/opportunities-ev), [Arbitrage](/en/api-reference/opportunities-arbitrage), [Middles](/en/api-reference/opportunities-middles) — endpoints with nested reference blocks +- [Event Matching](/en/concepts/event-matching) — how SharpAPI joins the same fixture across books