---
title: "Italian Bookmakers Odds API — 40+ ADM-Licensed Books in one JSON | odss-api"
description: "Sports odds API for the 40+ ADM-licensed Italian bookmakers that global odds APIs don't carry. Stable event_id, per-book last_update, free tier."
url: https://odss-api.com/en
---

# Italian bookmaker odds, in one API

Normalized odds from dozens of bookmakers — including the Italian books global APIs lack — in a stable JSON format. For your models, bots and tools.

● IT books on a continuous cycle · measured freshness stable event_id · last_update per quote self-serve · no card

```
# one request, all the odds for an event
curl "https://odss-api.com/api/v1/odds?sport=calcio&league=serie%20a" \
  -H "x-api-key: odss_live_..."

{ "count": 118, "offset": 0, "returned": 118, "state": "prematch", "odds": [{
  "event_id": "a3f9c1e07b2d4865", "event": "Inter - Milan",
  "league": "Serie A", "market": "1x2", "commence_time": "2026-08-23T18:45:00Z",
  "bookmakers": [
    { "key":"snai", "outcomes":{"HOME":2.10,"DRAW":3.40,"AWAY":3.60}, "last_update":"2026-07-14T10:32:05Z" },
    { "key":"bet365", "outcomes":{"HOME":2.05,"DRAW":3.50,"AWAY":3.70}, "last_update":"2026-07-14T10:28:12Z" },
    { "key":"leovegas", "outcomes":{"HOME":2.08,"AWAY":3.55}, "suspended":["DRAW"], "last_update":"2026-07-14T10:31:44Z" } ]}]}
```

## Three moves to integrate the odds

### Create a key

Sign up and generate an odss_live key in a minute. The Free plan is forever, no card required.

### Call /odds

One endpoint, all cross-book odds by event and market. Filter by sport, league, market and bookmaker.

### Integrate and sync

Stable event_id to recognize events, last_update for freshness, offset to read the whole schedule.

## The moat: Italian books.

### The ADM bookmakers global APIs don't have

Dozens of ADM-licensed Italian operators, plus international reference books and exchanges. The list active right now is at **/api/v1/bookmakers**, with an API key: no brand wall to take on trust. **country**, **playable_it** and **is_exchange** are response fields, not query parameters — the endpoint accepts none.

### Stable schema

A public, versioned JSON format: the engine's internal shape never leaks into your code.

### Reliable integration

Deterministic event_id for the whole prematch window, ISO last_update per book, offset pagination: no-surprise syncs.

### Honest freshness

Italian books run on a continuous cycle and the real freshness is measured and public, per book, on the status page; bet365 arrives via a third-party data provider under a contractual licence, with a cadence of a few minutes. Every quote declares its last_update: no stale numbers dressed up as live.

## The honest comparison.

Where we stand vs global APIs and the market average. No names, no promises.

Comparison against the average of the global/enterprise providers reviewed (Jul 2026). Our side is verifiable from the public endpoints and the docs.

## Bookmakers & leagues

Live numbers, counted from the feed right now — not a catalog inventory.

—

bookmakers active in the feed

—

sports priced right now

—

leagues on the board

The named list of the books active right now is at **GET /api/v1/bookmakers**, with the **country**, **playable_it**, **is_exchange** and **source** fields: it requires an API key (the Free one takes a minute, no card). Without a key, **GET /api/v1/leagues** — the source of the counts above — and **GET /api/v1/coverage** are public.

### Leagues on the board right now

Live data from the feed (public endpoint /api/v1/leagues): for each sport, the leagues currently priced. Names are the values for the league filter.

Loading the schedule…

The board follows the season: club football is naturally thinner in summer.

## Documentation

Base URL https://odss-api.com. Authenticate with the x-api-key: odss_live_… header or Authorization: Bearer. JSON responses, European decimal odds.

### GET /api/v1/mock/odds no key needed

Every endpoint has a twin under `/api/v1/mock/` that answers **right now, with no signup and no quota consumed**: same response shape, same parameters, same strict validation as the real feed. The prices are synthetic — `mock: true`, header `X-Odss-Mock: 1`, ids prefixed `mock_` — they are there to write and test your code, not to bet on.

```
curl "https://odss-api.com/api/v1/mock/odds?sport=calcio&limit=3"
```

Available: /mock/odds · /mock/odds/history · /mock/sports · /mock/bookmakers · /mock/leagues · /mock/status · /mock/stream (SSE). The `seed` parameter makes the payload reproducible: use it in CI instead of burning quota on every run.

On the REAL feed these are public with no key too: `/api/v1/leagues`, `/api/v1/coverage` and `/api/v1/status`.

### First call in 3 steps

#### Create a key

Sign up and generate a key in the dashboard. The Free plan is forever.

#### List sports

Verify the key with a call to /sports.

#### Get odds

Call /odds with sport and market: you get cross-book odds.

### GET /api/v1/odds example

```
curl "https://odss-api.com/api/v1/odds?sport=calcio&league=serie%20a&limit=5" \
  -H "x-api-key: odss_live_..."
```

```
const r = await fetch(
  "https://odss-api.com/api/v1/odds?sport=calcio&league=serie%20a&limit=5",
  { headers: { "x-api-key": "odss_live_..." } }
);
const { count, odds } = await r.json();
```

```
import requests
r = requests.get(
    "https://odss-api.com/api/v1/odds",
    params={"sport": "calcio", "league": "serie a", "limit": 5},
    headers={"x-api-key": "odss_live_..."},
)
data = r.json()  # { count, offset, returned, state, odds: [...] }
```

### GET /api/v1/odds

Current cross-book odds, grouped by event, market and line. Each record lists the bookmakers with their outcomes and the timestamp of their last update.

#### Parameters

| Parameter | Description |
| --- | --- |
| `sport` | Exact sport filter (e.g. calcio, tennis, basket). Values: see /api/v1/sports. |
| `market` | Canonical market: 1x2, ou, btts, dc, ah (Asian handicap), eh (European handicap), moneyline… |
| `bookmakers` | CSV list of book keys (e.g. snai,bet365). Values: see /api/v1/bookmakers. |
| `league` | Case-insensitive substring filter (e.g. serie a). Values: see /api/v1/leagues. |
| `event_id` | A single event, by exact id. |
| `state` | prematch (default), live (in-play, with current score and minute) or all (both). With live, if the in-play engine is off the list is empty and live_enabled=false. If the key has a feed scope (prematch-only or live-only), a state outside the scope returns 403 and all degrades to the allowed state. |
| `limit` | Records per page. Default 500, max 2000. |
| `offset` | Start index for pagination. Default 0. |

#### Response fields

| Field | Description |
| --- | --- |
| `count` | Total records matching the filters (across all pages). |
| `offset · returned` | Echo of the requested offset and the records actually returned in this page. |
| `odds[].event_id` | Deterministic event id: identical for every market of the same fixture and stable for the whole prematch window. |
| `odds[].event` | Normalized event name (Home - Away). |
| `odds[].sport · league` | Sport and league/competition of the event. |
| `odds[].home_team · away_team` | The two teams, when available. |
| `odds[].commence_time` | Event start, ISO 8601 UTC. |
| `odds[].market · line · scope · period` | Canonical market, optional line (e.g. 2.5), scope (e.g. team) and period (e.g. 1st half). |
| `odds[].state · score · minute` | state = prematch or live. For live: current score (e.g. "1-0") and minute (e.g. "63'"). Same event_id as prematch to correlate the fixture across the two states. |
| `…bookmakers[].key` | Bookmaker key, with country, playable_it and is_exchange. |
| `…bookmakers[].outcomes` | Outcome → decimal odds map (e.g. HOME: 2.10). |
| `…bookmakers[].suspended` | Outcomes this book prices but is **not taking bets on right now**. They are not in outcomes (a suspended outcome has no playable price) and are named here instead, so that «the book does not offer this outcome» and «it offers it and is closed right now» stay two distinct facts. **Optional field, and its absence means something**: if missing, that book's source does not publish the state; [] means it was read and nothing is suspended. Never read an absent field as an empty list. |
| `…bookmakers[].last_update` | ISO timestamp of that book's last successful odds update. |

#### Pagination

Repeat the call increasing offset by returned, as long as offset + returned < count. The board is live: count may shift slightly between pages.

```
GET /api/v1/odds?sport=calcio&limit=1000&offset=0
GET /api/v1/odds?sport=calcio&limit=1000&offset=1000
# … finché offset + returned < count
```

### GET /api/v1/sports

The sports currently available in the feed (the values for the sport parameter).

### GET /api/v1/bookmakers

The bookmakers active in the feed, with country (ISO 3166-1 alpha-2 code of the licensing country — IT, GB, US, SE… — or world when none is attributed), playable_it (true only for books holding an Italian ADM licence, i.e. playable from Italy: false for every other book in the feed, from sharp references like Pinnacle to the international brands), is_exchange (commission on winnings) and source (direct when we read the book ourselves, partner_feed when its prices reach us through a third-party data provider).

### GET /api/v1/leagues public, no key

The current schedule, aggregated: for each sport the priced leagues, with event and bookmaker counts. Useful to discover values for the league filter.

### GET /api/v1/stream Pro and Enterprise

Server-Sent Events: a hello event on connect, then odds events with the CHANGED records (same schema as /odds, each with its own state) and the removed ones, within ~10 seconds of the engine detecting them — no polling. Optional sport and state (prematch|live|all) parameters; initial snapshot via GET /odds?state=…. Data cadence stays the engine's (per-book freshness measured on the status page; bet365 via a third-party data provider under a contractual licence): the stream removes polling latency, last_update is authoritative. Max 3 concurrent streams; the connection counts as 1 quota request.

### GET /api/v1/odds/history

Odds change history for an event: one row every time a bookmaker moves a price on a group. Filters `event_id` (required), `book`, `market`, `from`/`to` (ISO), `limit`. Newest first: for a started event the first row is its closing line. Honours the key scope.

```
curl "https://odss-api.com/api/v1/odds/history?event_id=a3f9c1e07b2d4865&book=snai" \
  -H "x-api-key: odss_live_..."
```

### GET /api/v1/middles

Over/Under middles computed from the current feed: OVER on a low line at one book, UNDER on a high line at another. If the total lands inside the window both bets win. Fields `middle_window`, `hit_return_pct`, `miss_return_pct`, `safe` (no loss even when it misses). Filters: `sport`, `min_return`, `safe`, `limit`.

**Freshness rule:** a price older than `stale_after_seconds` (900s by default) stays in `/odds` responses with its `last_update`, but is **never paired** into a middle: a stale leg probably no longer exists on the bookmaker site. The applied threshold and the number of discarded legs are in the response.

```
curl "https://odss-api.com/api/v1/middles?sport=calcio&safe=true" \
  -H "x-api-key: odss_live_..."
```

### GET /api/v1/coverage public, no key

How many bookmaker **brands** have a valid price in the current feed, per region (Italy, USA, UK, world). It does not match the number of entries in `/api/v1/bookmakers`: that endpoint lists the queryable **keys**, where dedicated market lanes (e.g. `<brand>-corners`) count on their own, while here they are folded under the brand.

### POST /api/mcp MCP

MCP server (JSON-RPC 2.0) for AI agents and connectors (Claude, ChatGPT…). Auth with the same key (Authorization: Bearer odss_live_… or x-api-key). Tools: get_odds (with state=live), list_sports, list_bookmakers, list_leagues. Only tools/call uses quota; the handshake is free. Stateless: every request is self-contained.

```
curl -X POST https://odss-api.com/api/mcp \
  -H "Authorization: Bearer odss_live_..." -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"get_odds","arguments":{"sport":"calcio","state":"live","limit":5}}}'
```

### Webhook Enterprise

Register an https URL from the dashboard or via API — POST /api/account/webhooks with your account session (body &#123;url, sport?, state?&#125;; the secret is shown once, max 20 per account) — and receive odds changes via POST: same &#123;changed, removed&#125; payload as the stream. Each delivery is signed: X-Odss-Signature: t=<unix>,v1=<hex> = HMAC-SHA256 of «&#123;timestamp&#125;.&#123;body&#125;» with the webhook secret (verify it, reject old timestamps). https only, redirects not followed; endpoints that repeatedly fail auto-disable. Respond 2xx. One delivery can arrive as several consecutive POSTs, each signed on its own and numbered by the X-Odss-Page: page/total header: every body carries page, pages, changed_total and removed_total, so the first page already tells you how much is coming. Don't rate-limit the endpoint: a rejected page stops the ones after it.

### Limits, headers and errors

Every authenticated response includes X-RateLimit-Limit (your plan's monthly quota), X-RateLimit-Remaining and X-RateLimit-Reset (unix seconds when the window reopens; on the monthly-quota 429 the same instant is in the body as retry_at). The quota is a rolling 30-day window.

| Status | Description |
| --- | --- |
| `400` | Invalid request: unknown parameter, value outside the allowed set (e.g. state) or missing required parameter (e.g. event_id on /odds/history). The response body says which. |
| `401` | Missing, invalid or revoked key. |
| `403` | Out of scope: suspended account, feed outside the key's scope (e.g. live with a prematch-only key) or plan-gated feature (stream: Pro and Enterprise; webhooks: Enterprise). |
| `429` | Burst: per-minute requests of your plan exceeded. Retry-After: 60 header. |
| `429` | Monthly quota exhausted: upgrade or wait for the window. |
| `502` | Feed temporarily unavailable: retry with backoff. |

#### Parameters: no silent failures

On every /api/v1 endpoint a parameter we don't recognize is never ignored: if you write bookmaker instead of bookmakers you get a 400 with the wrong name, the list of the ones allowed on that endpoint and, if it's a typo, a suggestion for the right name. The comparison is exact: even Sport with a capital letter is rejected. The catalog endpoints (/sports, /bookmakers, /leagues, /coverage, /status) accept no parameters. We prefer an error right away over a 200 response with unfiltered data that looks correct: the 400 is deterministic, it should be fixed rather than retried, and it does not use quota.

The same rule applies to the tool arguments on the MCP server (POST /api/mcp): a name that doesn't exist, or a wrong type such as a list where a CSV string is expected, gets a JSON-RPC -32602 error instead of being ignored. The error.data field carries the allowed names, so the agent corrects itself.

```
curl "https://odss-api.com/api/v1/odds?bookmaker=snai" -H "x-api-key: odss_live_..."

HTTP/1.1 400 Bad Request
{
  "error": "Parametro sconosciuto: \"bookmaker\" (forse intendevi \"bookmakers\"?). Ammessi su questo endpoint: bookmakers, content, event_id, league, limit, market, offset, player, sport, state"
}
```

### Machine-readable · contract & agents

To generate clients, SDKs or use the API from an AI agent: the OpenAPI 3.1 contract and a concise LLM guide are public and always in sync.

| Field | Description |
| --- | --- |
| [/openapi.json](https://odss-api.com/openapi.json) | OpenAPI 3.1 contract (endpoints, parameters, schemas, x-api-key auth). |
| [/llms.txt](https://odss-api.com/llms.txt) | Markdown guide for LLMs (llmstxt.org): summary and links to resources. |
| [/postman_collection.json](https://odss-api.com/postman_collection.json) | Postman collection: import it and set the x-api-key variable to try the endpoints right away. |
| [/sdk/odss_api.py](https://odss-api.com/sdk/odss_api.py) | Official Python SDK (single-file, zero dependencies): typed client with automatic pagination and live support. |
| [/sdk/odss-api.ts](https://odss-api.com/sdk/odss-api.ts) | Official TypeScript SDK (single-file, zero dependencies): types, async iterator and an SSE stream helper. |
| [/.well-known/api-catalog](https://odss-api.com/.well-known/api-catalog) | API catalog (RFC 9727, JSON linkset). |

### Usage license

Internal use (models, bots, analysis, backtests) is included in every plan. Redistributing the data — e.g. showing it to your product's end users — requires the **Display Redistribution** licence (Enterprise add-on, +€120/month), which covers display only. Creating, powering or commercialising **surebet/arbitrage** services, **value betting** or equivalents requires the Surebet API instead, the plan that includes the licence to resell the computed surebets: €950/month + VAT, from the site. Redistributing the API or the raw data stays outside every plan: for that, write to info@praxis3.it.

## The right plan for your volume.

Same coverage on every plan: you only pay for volume. Start free, cancel anytime.

### Free

To explore the API. Forever, no card.

- 500 requests / month

- 30 requests / min

- Full coverage: every sport and every book in the feed

### Hobby

For personal projects and small bots.

- 10,000 requests / month

- 60 requests / min

- Full coverage: every sport and every book in the feed

### Starter

For bots and production integrations.

- 100,000 requests / month

- 120 requests / min

- Full coverage: every sport and every book in the feed

### Pro

For platforms and high volumes.

- 500,000 requests / month

- 600 requests / min

- Priority support

### Enterprise

For platforms, companies and resellers: configure volume, rate and license — the price updates by itself and you activate at checkout, no negotiation.

Authorises you to **show** the data to your product's end users — websites, apps, dashboards, widgets, comparison tools (without it, use stays internal). It does **not** authorise creating or commercialising surebet/arbitrage services, value betting or equivalent platforms, nor redistributing the API or the raw data: those need a dedicated commercial licence. [Read the license →](https://odss-api.com/#)

Declared use — required by the License, §8

The SaaS license authorises you to show the data to your end users: state who you are and where you show it. Filled in once, now.

- SSE streaming included (/api/v1/stream)

- Quota and rate configured on your account

- Automatic activation on payment, cancel anytime

By proceeding you accept the Enterprise & Redistribution License (readable from the link above) in addition to the Terms of service.

Prices shown are **exclusive of VAT**. Applicable tax is added at checkout based on your country and tax status: **22% for Italy** (including businesses with an Italian VAT number); **reverse charge, 0% tax**, for businesses in **other EU Member States** with a valid VAT number; **outside the scope of Italian VAT** for non-EU customers. The total amount you pay is the one shown in the checkout summary, which you confirm before placing your order (§4 of the Terms) · Payments via Stripe · one-click cancellation from the portal · quota is a rolling 30-day window

## Three tiers, one engine.

Normalized odds are the first tier. If what you want to sell are the arbitrages themselves, you need a different tier: the surebets already computed, with the right to resell them included in the subscription.

Tier 1 · self-serve

### Odds API

Normalized odds and data. From the Free plan to Enterprise, public pricing, instant activation.

Tier 2 · self-serve

### Surebet API

The surebets already found and computed by the engine, refreshed every 180 seconds, not just the odds. An API plan at €950/month + VAT, resale licence included.

Tier 3 · under contract

### Surebet White Label

The complete platform, under your brand, ready to be commercialised. €2,000/month + VAT.

### Surebet API

For whoever builds a product of their own on top of it. It does not return odds alone: it returns the surebets already identified and computed by our engine, refreshed every 180 seconds. If you have nobody to resell them to, you do not need it: surebett.app is enough.

Declared use — required by the Surebet API Commercial License

The Surebet API Commercial License authorises you to use the computed opportunities in a product of your own aimed at end users: state who you are and where you publish them. Filled in once, now.

Activated as soon as the payment goes through, cancel in one click from the portal. It is a plan of its own and does not stack on a listed plan: if the account already has a paid one active, it has to be cancelled first. By proceeding you enter into the Surebet API Commercial License, within the limits of the use you declared above, and accept the Terms of service (§5).

- Event and market

- Bookmakers involved and the odds of each leg

- Arbitrage percentage/margin

- Optimal stakes

- Odds timestamp and freshness

- The identifiers needed for integration

The fields listed are those provided **where available**: the response carries what the engine actually computed for that event. The resale licence is included in the subscription: you may use the computed surebets in a commercial product of your own, aimed at your end users, within the limits of the declared use and of the Terms. It does not cover the White Label, which remains a separate contract.

### Surebet White Label

For companies that do not want to build the platform themselves: the complete Surebet platform, delivered as a service under your own brand.

- Surebet engine

- Data and updates

- Complete frontend

- Logo, name and colour customisation

- Hosting and infrastructure

- Maintenance and updates

The software, the engine and the source code **remain our property** and are granted for use under the White Label contract.

The «Display Redistribution» licence of the API plans authorises you to **show** the odds inside your product: it does not authorise creating or commercialising surebet/arbitrage services, value betting or substantially equivalent platforms, nor redistributing the API or the raw data. Those uses require the Surebet API Commercial License or the White Label contract — see the commercial licences and the Terms, §5.

## Frequently asked questions.

Internal use — your own models, bots, analysis, tools — is included in every plan. Showing the data to your product's end users requires the Display Redistribution licence (Enterprise add-on): it authorises display only. If what you want to sell are the surebets — arbitrage, value betting or equivalent services — you need the Surebet API, bought from the site like any other API plan: €950/month + VAT, with the licence to resell them **included** in the subscription and the declared-use form required before payment. If you have nobody to resell to, you do not need it: surebett.app is enough. The complete platform under your own brand remains the White Label, under contract — see Surebet API and White Label.

Italian bookmakers on a continuous cycle — the REAL freshness, measured per book (p50/p95), is public on the status page; bet365 arrives via a third-party data provider under a contractual licence, with a cadence of a few minutes. You don't have to take our word for it: every quote in the response carries its last_update.

The Free plan is forever and has the same coverage as the paid plans: it's the best way to verify the data. If you need more volume for an evaluation, write to info@praxis3.it.

Same engine, two products: odss-api sells the raw normalized odds to build on; surebett.app is the finished product, with arbitrages already computed and balanced stakes.

Yes: the API exposes the odds of the Italian licensees currently in the feed, filterable with the bookmakers parameter. The list active right now is at GET /api/v1/bookmakers, which requires an API key (the Free one takes a minute, no card); without a key, /api/v1/leagues and /api/v1/coverage are public. Every quote carries its last_update.

Yes: the API returns standard JSON, so it goes straight into Postgres, SQLite, pandas or Google Sheets. With the Python and TypeScript SDKs it takes a few lines; the Free plan (500 requests/month) is enough to try, no card.

Here: Free 500 requests/month without a card, Hobby €19/month + VAT (10,000), Starter €79/month + VAT (100,000), Pro €159/month + VAT (500,000), Enterprise from €199 + VAT. All amounts are **exclusive of VAT**: for an Italian consumer 22% is added. Businesses in other EU Member States with a valid VAT number are subject to reverse charge (0% tax); for non-EU customers the supply is outside the scope of Italian VAT. The total is always shown in the checkout summary, which you confirm before the order (§4 of the Terms). Same coverage on every plan: you only pay for volume.

Italian books run on a continuous cycle and freshness is measured, not promised: p50 and p95 over the last 24h are public on the status page, per book. SSE streaming for push; in-play has its own feed.

We need these to issue the invoice or receipt for your subscription.

These end up on the invoice. With an Italian VAT number you also need the SDI recipient code or a PEC address.

[Forgot your password?](https://odss-api.com/#)

### Contact the team

Write to us: we open a ticket and reply by email. No bots.
