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

# Odds

> Query current bookmaker odds across all scraped markets.

## GET /api/odds

Returns current bookmaker odds — one row per `(event × bookmaker × market_type × period)` combination. The `odds` field is an object keyed by selection text, making it easy to compare prices across bookmakers for the same market.

For the full market breakdown of a single event (all bookmakers, all markets, grouped), use `GET /api/events/{id}` instead.

### Query Parameters

| Parameter     | Type    | Default | Description                                                 |
| ------------- | ------- | ------- | ----------------------------------------------------------- |
| `sport`       | string  | —       | Filter by sport name (e.g. `Football`, `Tennis`)            |
| `competition` | string  | —       | Filter by competition code (e.g. `EPL`, `NBA`)              |
| `bookmaker`   | string  | —       | Filter by bookmaker name (e.g. `Winamax`, `Betclic`)        |
| `market_type` | string  | —       | Filter by market type (e.g. `moneyline`, `spread`, `total`) |
| `is_live`     | boolean | —       | `true` = in-play only, `false` = pre-match only             |
| `limit`       | integer | `100`   | Max rows returned, up to 500                                |

### Response

```json theme={null}
{
  "data": [
    {
      "bookmaker": "Betsson",
      "match_name": "Crystal Palace - West Ham United",
      "competition": "EPL",
      "sport": "Football",
      "market_type": "moneyline",
      "period": 0,
      "is_live": false,
      "odds": {
        "Crystal Palace": 3.40,
        "Draw": 3.25,
        "West Ham United": 2.10
      },
      "match_date": "2026-04-20T20:00:00Z",
      "scraped_at": "2026-04-20T14:11:09Z",
      "url": "https://www.betsson.fr/paris-sportifs/event/4237119.1"
    },
    {
      "bookmaker": "Winamax",
      "match_name": "Crystal Palace - West Ham United",
      "competition": "EPL",
      "sport": "Football",
      "market_type": "moneyline",
      "period": 0,
      "is_live": false,
      "odds": {
        "Crystal Palace": 3.35,
        "Draw": 3.20,
        "West Ham United": 2.15
      },
      "match_date": "2026-04-20T20:00:00Z",
      "scraped_at": "2026-04-20T14:07:11Z",
      "url": "https://www.winamax.fr/paris-sportifs/sports/..."
    },
    {
      "bookmaker": "Unibet.fr",
      "match_name": "Cleveland Cavaliers / Toronto Raptors",
      "competition": "NBA",
      "sport": "Basketball",
      "market_type": "player_prop",
      "period": 0,
      "is_live": false,
      "odds": {
        "RJ Barrett Rebounds Over 4.5": 2.12,
        "RJ Barrett Rebounds Under 4.5": 1.72
      },
      "match_date": "2026-04-20T23:00:00Z",
      "scraped_at": "2026-04-20T13:51:28Z",
      "url": null
    }
  ],
  "meta": {
    "count": 12847,
    "rate_limit_remaining": 295
  }
}
```

### Response Fields

| Field         | Type                    | Description                                              |
| ------------- | ----------------------- | -------------------------------------------------------- |
| `bookmaker`   | string                  | Bookmaker name                                           |
| `match_name`  | string                  | Canonical event name from the scraper                    |
| `competition` | string                  | Competition code                                         |
| `sport`       | string                  | Sport derived from competition code                      |
| `market_type` | string                  | Market type — see table below                            |
| `period`      | integer                 | Time segment (0=full time, 1=1st half, etc.)             |
| `is_live`     | boolean                 | `true` if this is an in-play market                      |
| `odds`        | object                  | Keyed by selection text → decimal odds value             |
| `match_date`  | ISO-8601 string \| null | Scheduled kick-off (UTC)                                 |
| `scraped_at`  | ISO-8601 string         | When these odds were last scraped                        |
| `url`         | string \| null          | Direct deep-link to this market on the bookmaker site    |
| `liquidity`   | float \| null           | Pinnacle max bet size (only populated for Pinnacle rows) |

### `odds` Object Format

The `odds` field groups all selections for this `(bookmaker, event, market, period)` combination into a single object. Selection texts vary by market type:

| Market Type            | Typical `odds` keys                                           |
| ---------------------- | ------------------------------------------------------------- |
| `moneyline` (football) | `"Home Team"`, `"Draw"`, `"Away Team"`                        |
| `moneyline` (other)    | `"Home Team"`, `"Away Team"`                                  |
| `spread`               | `"Home Team +1.5"`, `"Away Team -1.5"`                        |
| `total`                | `"Over 2.5"`, `"Under 2.5"`                                   |
| `btts`                 | `"Yes"`, `"No"`                                               |
| `double_chance`        | `"1X"`, `"X2"`, `"12"`                                        |
| `player_prop`          | `"Player Name Stat Over X.X"`, `"Player Name Stat Under X.X"` |
| `team_total`           | `"Home Over 1.5"`, `"Home Under 1.5"`                         |

***

## GET /api/odds/live

Same as `GET /api/odds` but returns only in-play events. Requires **Pro+ Live** plan.

### Query Parameters

Identical to `GET /api/odds` (same filters, same `limit`).

### Notes

* Live odds update every 5–10 seconds. Poll accordingly.
* Bookmakers with live coverage: Betclic, Winamax (selected events), Unibet.fr (selected events).

***

## GET /api/odds/{bookmaker}

Returns all current odds for a specific bookmaker. Equivalent to `GET /api/odds?bookmaker={bookmaker}` but slightly more efficient.

### Path Parameter

| Parameter   | Description                                                                                     |
| ----------- | ----------------------------------------------------------------------------------------------- |
| `bookmaker` | Exact bookmaker name (e.g. `Winamax`, `Betclic`) — use `GET /api/bookmakers` to get valid names |

### Query Parameters

| Parameter     | Type    | Default | Description                |
| ------------- | ------- | ------- | -------------------------- |
| `sport`       | string  | —       | Filter by sport            |
| `competition` | string  | —       | Filter by competition code |
| `market_type` | string  | —       | Filter by market type      |
| `is_live`     | boolean | —       | In-play filter             |
| `limit`       | integer | `100`   | Max rows, up to 500        |

### Response

Same format as `GET /api/odds`.

***

## Code Examples

```bash theme={null}
# All EPL moneyline odds
curl "https://api.oddsstream.io/api/odds?competition=EPL&market_type=moneyline" \
  -H "X-Api-Key: os_live_YOUR_KEY"

# All Betclic odds
curl "https://api.oddsstream.io/api/odds/Betclic" \
  -H "X-Api-Key: os_live_YOUR_KEY"

# All Winamax football spreads
curl "https://api.oddsstream.io/api/odds/Winamax?sport=Football&market_type=spread" \
  -H "X-Api-Key: os_live_YOUR_KEY"

# Live basketball odds (Pro+ Live)
curl "https://api.oddsstream.io/api/odds/live?sport=Basketball" \
  -H "X-Api-Key: os_live_YOUR_KEY"
```

```python theme={null}
import requests

API_KEY = "os_live_YOUR_KEY"

# Get all LIG1 moneyline rows
resp = requests.get(
    "https://api.oddsstream.io/api/odds",
    params={"competition": "LIG1", "market_type": "moneyline", "limit": 200},
    headers={"X-Api-Key": API_KEY}
)
rows = resp.json()["data"]

# Group by match name to compare bookmakers
from collections import defaultdict
by_match = defaultdict(list)
for row in rows:
    by_match[row["match_name"]].append(row)

# Find best odds per selection
for match, bookmaker_rows in by_match.items():
    print(f"\n{match}")
    # Collect all selections from all bookmakers
    all_selections = {}
    for row in bookmaker_rows:
        for sel, odds in row["odds"].items():
            if sel not in all_selections or odds > all_selections[sel]["odds"]:
                all_selections[sel] = {"odds": odds, "bookmaker": row["bookmaker"]}
    for sel, best in all_selections.items():
        print(f"  {sel}: {best['odds']} @ {best['bookmaker']}")
```

```javascript theme={null}
// Poll all EPL odds every 30 seconds
async function pollOdds() {
  const resp = await fetch(
    "https://api.oddsstream.io/api/odds?competition=EPL&market_type=moneyline&limit=500",
    { headers: { "X-Api-Key": "os_live_YOUR_KEY" } }
  );
  const { data, meta } = await resp.json();
  
  console.log(`${data.length} odds rows, ${meta.rate_limit_remaining} requests remaining`);
  
  // Build lookup: match → bookmaker → odds
  const lookup = {};
  for (const row of data) {
    if (!lookup[row.match_name]) lookup[row.match_name] = {};
    lookup[row.match_name][row.bookmaker] = row.odds;
  }
  return lookup;
}

setInterval(pollOdds, 30_000);
```
