> ## Documentation Index
> Fetch the complete documentation index at: https://enterprise.predexon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sports Markets

> How Predexon's unified sports market discovery works across venues

## Overview

Predexon's sports discovery API provides a **unified cross-venue view of sports betting markets**. A single "game" surfaces every venue that lists that game, with each venue's native market data (prices, volume, liquidity, outcomes) nested underneath.

Data is sourced from:

* **Polymarket**
* **Kalshi**
* **Limitless**
* **Opinion**
* **Predict.fun**

All endpoints are served under `/v2/sports/*` and require your **data key** in the `x-api-key` header. (The trading key used by the [Order Router](/concepts/order-router) on `trade.predexon.com` is a separate credential.)

***

## Data Model

The structure below describes the per-venue response from [`GET /v2/sports/markets`](/api-reference/sports/markets). For a compact game/outcome list, see [`GET /v2/sports/games`](/api-reference/sports/games).

### Game

A **game** is a single real-world sporting event (e.g. "Atlanta Hawks vs. New York Knicks on April 18, 2026"). Predexon identifies each game with a canonical `game_id` of the form:

```
{league}-{team_code_a}-{team_code_b}-{YYYY-MM-DD}
```

Example: `nba-atl-nyk-2026-04-18`

Team codes are sorted alphabetically to guarantee the same two teams on the same date always produce the same `game_id` - regardless of which venue is the source.

`game_id` is the broad sports fixture. It is separate from `event_id`, which identifies the canonical market/question scope attached to that game. For the current sports v1, only `game_winner` markets are exposed, so `game_id` and `event_id` often have the same value. Future spreads, totals, and props can share a `game_id` while using more specific `event_id` values.

### Market Types

Each game has one or more `market_types`, representing the kind of bet being placed. Today the only supported type is:

| Market Type   | Description                     |
| ------------- | ------------------------------- |
| `game_winner` | Bet on which team wins the game |

Future additions (`game_spread`, `game_total_points`, etc.) will appear as additional entries under a game's `market_types` array.

### Venue Blocks

Under each `market_type`, each venue that lists that market appears as its own **venue block**. Venue blocks contain:

* Venue-native identifiers (`market_id`, `market_slug`, `condition_id`)
* Live market-level metadata (`market_title`, `volume`, `liquidity`, `end_time`)
* An array of `outcomes` specific to that venue

**Identifier fields are venue-specific.** Kalshi uses tickers and has no `condition_id` or `market_slug`, so those fields are omitted from Kalshi venue blocks. Polymarket, Limitless, and Predict.fun all use on-chain `condition_id`s. Opinion uses a numeric `market_id`.

### Outcomes

Each venue block has an `outcomes` array listing the individual tradeable sides of that market. Every outcome includes:

| Field           | Description                                                                                       |
| --------------- | ------------------------------------------------------------------------------------------------- |
| `outcome`       | Canonical outcome code (team code like `"atl"`, or `"draw"`)                                      |
| `outcome_label` | Human-readable label (`"Atlanta Hawks"`, `"Draw"`)                                                |
| `event_id`      | Canonical market/question identifier. For current `game_winner` rows this often equals `game_id`. |
| `condition_id`  | On-chain condition ID for this outcome's market (Polymarket/Limitless/Predict only)               |
| `market_slug`   | Venue-native slug for this outcome's market                                                       |
| `market_id`     | Venue-native identifier (Kalshi ticker / Opinion integer only)                                    |
| `tokens`        | YES and NO sides with prices and identifiers (see below)                                          |

### Tokens & Prices

Each outcome has a `tokens` object with side entries. Prices live on the token side, not on the outcome. Most current sports v1 listings expose the tradable `yes` side for each canonical outcome; `no` may be omitted or empty when the venue/listing does not expose a distinct routable NO side in the canonical sports projection.

| Field                    | Description                                                                                                                                                                |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokens.yes.price`       | Current YES-side price (0.0 - 1.0). The cost to bet FOR this outcome. `null` if unpriced.                                                                                  |
| `tokens.yes.token_id`    | Venue-native token ID for the YES side. Present for on-chain venues (Polymarket, Limitless, Predict, Opinion). **Not present for Kalshi** (Kalshi has no on-chain tokens). |
| `tokens.yes.predexon_id` | Predexon canonical outcome ID. Present on routable listings. Use for routing and outcome lookup.                                                                           |
| `tokens.no.price`        | Current NO-side price (0.0 - 1.0). The cost to bet AGAINST this outcome. `null` if unpriced.                                                                               |
| `tokens.no.token_id`     | Venue-native token ID for the NO side. Same presence rules as YES.                                                                                                         |
| `tokens.no.predexon_id`  | Predexon canonical outcome ID for a distinct NO listing when exposed. May be omitted.                                                                                      |

<Warning>
  `yes.price + no.price` may not equal 1.0 — the spread represents the venue's bid-ask spread or overround. For venues where only one side has been quoted, the other side may be `null`.
</Warning>

### predexon\_id

A `predexon_id` is Predexon's canonical identifier for one tradeable outcome, not a venue-native token. The same outcome across venues shares the same `predexon_id`.

Example: if Kalshi, Polymarket, and Predict.fun all list "Arizona Diamondbacks win" for the same game, each venue listing returns the same canonical `predexon_id`.

Use `predexon_id` for order routing, orderbook subscriptions, and as the key for cross-venue outcome lookups via `GET /v2/sports/outcomes/{predexon_id}`.

Identifier cleanup:

| Field           | Meaning                                                     |
| --------------- | ----------------------------------------------------------- |
| `predexon_id`   | Canonical Predexon outcome ID shared across matched venues. |
| `game_id`       | Broad real-world sports game.                               |
| `event_id`      | Canonical market/question scope attached to a game.         |
| `token_id`      | Venue-native executable token/side ID where applicable.     |
| `market_id`     | Venue-native market ID where the venue has one.             |
| `market_ticker` | Kalshi ticker.                                              |
| `condition_id`  | CTF condition ID, not an outcome ID.                        |

***

## Cross-Venue Matching

The same outcome on different venues shares the same canonical `predexon_id`. To find all executable venue listings for a given outcome:

```
GET /v2/sports/outcomes/px-uvtpjis2k7bj
```

Returns every venue listing for that canonical outcome, including venue-native identifiers like Kalshi tickers, Polymarket condition IDs, and token IDs.

Matching is performed **deterministically** using team code mappings curated by Predexon. No LLMs or probabilistic matching - if two venues list the same team on the same date, they match.

***

## Live Game State

Live scores and game state are exposed separately from market discovery:

| Endpoint                        | Purpose                                 |
| ------------------------------- | --------------------------------------- |
| `GET /v2/sports/live`           | List live-state snapshots by `game_id`. |
| `GET /v2/sports/live/{game_id}` | Fetch one live-state snapshot.          |

Live state keys off `game_id`, the broad real-world game. It does not key off `event_id`, because future spreads, totals, and props can all belong to the same game while using different canonical market/question IDs.

When live state is not yet available for a game, the endpoint can still return a game shell with `reliability.state = "no_data"` and null score fields. Source-level snapshots are available with `include_sources=true`.

See [Sports Live State](/concepts/sports-live-state) for reliability semantics and the websocket update shape.

***

## Dates & Times

### `game_date`

The **calendar date** of the game in its sport's primary local region:

* **US sports** (NBA, NHL, MLB, NFL, CFB, MLS): **Eastern Time (ET)**
* **European football** (EPL, La Liga, Serie A, Ligue 1, Bundesliga, UCL, UEL, etc.): **UTC**

This matches the convention used by the venues' own slugs. A late-night Lakers game on Apr 15 PT will be labeled `2026-04-15` (not April 16) because ET is the reference.

Format: `YYYY-MM-DD`.

### `game_date_timezone`

Game objects returned by `/v2/sports/markets` include a `game_date_timezone` field indicating which timezone `game_date` refers to. Possible values: `"US/Eastern"` or `"UTC"`.

Use this to correctly interpret `game_date` and the `game_date`, `game_date_from`, and `game_date_to` query filters. For example, an NBA game at 10:30 PM ET on April 23 has `game_date: "2026-04-23"` and `game_date_timezone: "US/Eastern"` — even though in UTC it's already April 24.

<Warning>
  When filtering by `game_date`, pass dates in the sport's local timezone, not UTC. For NBA games, use the Eastern Time date. For EPL games, use the UTC date. The `game_date_timezone` field on `/v2/sports/markets` responses tells you which convention applies.
</Warning>

### `end_time`

The timestamp when the venue's market **stops accepting trades**. This is typically around game start but can be earlier (pre-game lock) or later (some venues keep markets open during live events).

Format: **ISO-8601 with UTC offset**, e.g. `2026-04-18T22:00:00+00:00`.

<Info>
  `end_time` semantics vary slightly per venue:

  * **Polymarket**: market close time (`endDate`)
  * **Kalshi**: `close_time`
  * **Opinion**: `cutoffAt`
  * **Limitless**: not currently indexed - returned as `null`
  * **Predict.fun**: not currently indexed - returned as `null`
</Info>

***

## Venue Coverage

Not every venue lists every sport. Current coverage:

| League           |  Code | Polymarket | Kalshi | Limitless | Opinion | Predict.fun |
| ---------------- | :---: | :--------: | :----: | :-------: | :-----: | :---------: |
| NBA              | `nba` |      ✓     |    ✓   |     -     |    ✓    |      ✓      |
| NHL              | `nhl` |      ✓     |    ✓   |     -     |    -    |      ✓      |
| MLB              | `mlb` |      ✓     |    ✓   |     -     |    -    |      ✓      |
| MLS              | `mls` |      ✓     |    ✓   |     -     |    -    |      -      |
| Premier League   | `epl` |      ✓     |    ✓   |     ✓     |    ✓    |      ✓      |
| Serie A          | `sea` |      ✓     |    ✓   |     ✓     |    ✓    |      ✓      |
| La Liga          | `lal` |      ✓     |    ✓   |     ✓     |    ✓    |      ✓      |
| Ligue 1          | `fl1` |      ✓     |    ✓   |     ✓     |    ✓    |      ✓      |
| Bundesliga       | `bun` |      ✓     |    ✓   |     ✓     |    -    |      ✓      |
| Champions League | `ucl` |      ✓     |    ✓   |     ✓     |    -    |      -      |
| Europa League    | `uel` |      ✓     |    ✓   |     ✓     |    -    |      -      |
| Eredivisie       | `ere` |      ✓     |    ✓   |     -     |    -    |      -      |
| Brasileirao      | `bra` |      ✓     |    ✓   |     -     |    -    |      -      |

This matrix reflects **current** coverage and will change as venues add or drop leagues. Use `GET /v2/sports/categories` for the live, always-up-to-date list.

***

## 2-way vs 3-way Markets

### 2-way (US sports)

NBA, NHL, NFL, MLB, CFB games have two outcomes: Team A wins or Team B wins. Each venue block contains exactly 2 outcomes.

Example outcomes array for an NBA game on Polymarket:

```json theme={null}
[
  {
    "outcome": "atl",
    "outcome_label": "Atlanta Hawks",
    "condition_id": "0xc3b0...",
    "market_slug": "nba-atl-nyk-2026-04-18",
    "tokens": {
      "yes": { "token_id": "17221...", "predexon_id": "px-uvt...", "price": 0.33 },
      "no": { "token_id": "98267...", "predexon_id": "px-xcu...", "price": 0.67 }
    }
  },
  {
    "outcome": "nyk",
    "outcome_label": "New York Knicks",
    "condition_id": "0xc3b0...",
    "market_slug": "nba-atl-nyk-2026-04-18",
    "tokens": {
      "yes": { "token_id": "98267...", "predexon_id": "px-xcu...", "price": 0.67 },
      "no": { "token_id": "17221...", "predexon_id": "px-uvt...", "price": 0.33 }
    }
  }
]
```

### 3-way (Football)

EPL, Serie A, La Liga, Ligue 1, Bundesliga, UCL, UEL, etc. have three outcomes: Team A wins, Team B wins, or Draw. On Polymarket and Predict.fun, each outcome is a separate on-chain market (different `condition_id` per outcome) - Predexon aggregates them into a single venue block so the consumer doesn't need to deal with this venue-native complexity.

Example outcomes array for an EPL game on Limitless:

```json theme={null}
[
  {
    "outcome": "bou",
    "outcome_label": "Bournemouth",
    "condition_id": "0xaaa...",
    "market_slug": "bournemouth-177...",
    "tokens": {
      "yes": { "token_id": "123...", "predexon_id": "px-...", "price": 0.28 },
      "no": { "token_id": "456...", "predexon_id": "px-...", "price": 0.72 }
    }
  },
  {
    "outcome": "draw",
    "outcome_label": "Draw",
    "condition_id": "0xbbb...",
    "market_slug": "draw-177...",
    "tokens": {
      "yes": { "token_id": "789...", "predexon_id": "px-...", "price": 0.25 },
      "no": { "token_id": "012...", "predexon_id": "px-...", "price": 0.75 }
    }
  },
  {
    "outcome": "new",
    "outcome_label": "Newcastle",
    "condition_id": "0xccc...",
    "market_slug": "newcastle-177...",
    "tokens": {
      "yes": { "token_id": "345...", "predexon_id": "px-...", "price": 0.48 },
      "no": { "token_id": "678...", "predexon_id": "px-...", "price": 0.52 }
    }
  }
]
```

Venue-level fields (`volume`, `liquidity`) are **summed** across the 3 underlying markets. `end_time` is the latest of the 3.

***

## Data Freshness

* **Game structure** (which games exist, which venues cover them): updated in near real-time as venues list new markets.
* **Prices, volume, liquidity**: read live from each venue's indexer state table on every request. Lag is typically sub-second.
* **End times, titles, labels**: populated at ingestion time; updated when the venue publishes metadata changes.

Responses are cached for 60 seconds by default to protect venue databases under load. Trading decisions requiring fresher data should consult the venue's orderbook endpoints directly.

***

## See Also

The `predexon_id` values returned by the discovery endpoints are the input to the [Order Router](/concepts/order-router). Pass the canonical `predexon_id`, and the router executes across every routed venue that lists the same outcome.
