Crea la chiave
Registrati con la tua email. La chiave Free si genera subito, senza carta, e la vedi una volta sola: salvala dove tieni i segreti.
export ODSS_KEY="odss_live_…"
API di quote sportive · per sviluppatori e piattaforme
Un solo formato JSON per calcio, tennis, basket e tutti gli altri sport del palinsesto. Ogni quota porta il suo last_update, e la freschezza del feed è misurata e pubblica.
curl "https://odss-api.com/api/v1/mock/odds?sport=calcio&market=1x2&limit=2"
from odss_api import OdssApi
api = OdssApi.mock()
page = api.odds(sport="calcio", market="1x2", limit=2)
import { OdssApi } from "./odss-api";
const api = OdssApi.mock();
const page = await api.odds({ sport: "calcio", market: "1x2", limit: 2 });
Feed vero: /api/v1/odds con l'header x-api-key · SDK Python · TypeScript
{
"mock": true,
"notice": "Dati SINTETICI a scopo di sviluppo: prezzi inventati, nessun rapporto con i listini reali dei book. Feed vero: /api/v1/* con chiave.",
"count": 7, "offset": 0, "returned": 2, "state": "prematch",
"odds": [
{
"event_id": "mock_39b522d4",
"event": "Juventus - Inter",
"sport": "calcio", "league": "Serie A",
"market": "1x2",
"bookmakers": [
{
"key": "mockbook_it_1", "country": "IT", "playable_it": true,
"is_exchange": false, "family": "mockplat_a",
"outcomes": { "HOME": 2.27, "DRAW": 3.14, "AWAY": 3.06 },
"last_update": "2026-09-23T23:59:00.000Z"
},
{
"key": "mockbook_it_2", "country": "IT", "playable_it": true,
"is_exchange": false, "family": "mockplat_a",
"outcomes": { "HOME": 2.8, "DRAW": 3.45, "AWAY": 2.46 },
"suspended": [],
"last_update": "2026-09-23T23:58:23.000Z"
},
{
"key": "mockbook_it_3", "country": "IT", "playable_it": true,
"is_exchange": false, "family": "mockplat_a",
"outcomes": { "HOME": 3.9, "DRAW": 2.42 },
"suspended": ["AWAY"],
"last_update": "2026-09-23T23:57:46.000Z"
}
]
}
]
}
Il campo notice è sempre in italiano, qualunque sia la lingua della pagina.
Età delle quote italiane che ricevi, sulle ultime 24 ore. Come la misuriamo
Come funziona
Registrati con la tua email. La chiave Free si genera subito, senza carta, e la vedi una volta sola: salvala dove tieni i segreti.
export ODSS_KEY="odss_live_…"
Filtra per sport, lega e mercato con i nomi del feed. Un parametro che non esiste risponde 400 e ti suggerisce quello giusto.
curl "https://odss-api.com/api/v1/odds?sport=calcio&market=1x2" \
-H "x-api-key: $ODSS_KEY"
Ogni quota dice quando è stata letta (last_update); ogni risposta dice quante richieste ti restano e quando la quota si azzera.
X-RateLimit-Limit: 100000
X-RateLimit-Remaining: 99870
X-RateLimit-Reset: 1791763200
Freschezza
Non promettiamo il tempo reale: misuriamo l'età delle quote e la pubblichiamo, così decidi tu quanto fidarti di un prezzo.
Ogni 2 minuti, sullo snapshot che l'API sta servendo, misuriamo l'età di ogni quota pre-partita dei book italiani (adesso − last_update): è l'età delle quote che ricevi, non quella dentro il motore. p50 e p95 sono la mediana dei campioni delle ultime 24 ore; il tratteggio è il ciclo con cui il motore rilegge un book.
Non è l'uptime, che non dichiariamo, e non è la latenza della tua richiesta: è quanto è vecchio il prezzo che ricevi. Un limite, detto: last_update è la fine della lettura del book, e nelle letture di dettaglio che durano minuti le prime righe lette sono un po' più vecchie del loro timbro.
Prodotto
REST per interrogare e streaming per ricevere, con una documentazione leggibile anche dalle macchine. Lo storico dei movimenti non è ancora attivo.
Stessi nomi di sport, mercati ed esiti per book ADM, esteri ed exchange. Un mercato che non sappiamo mappare con certezza esce come other:<etichetta>, mai indovinato.
| bookmakers[].key | HOME | DRAW | AWAY | last_update |
|---|---|---|---|---|
| mockbook_it_1 | 2.27 | 3.14 | 3.06 | 23:59:00Z |
| mockbook_it_2 | 2.80 | 3.45 | 2.46 | 23:58:23Z |
| mockbook_it_3 | 3.90 | 2.42 | suspended | 23:57:46Z |
| mockbook_it_4 | 3.16 | 2.64 | 2.58 | 23:57:09Z |
| mockbook_it_5 | 2.43 | 2.42 | 3.66 | 23:56:32Z |
| mockbook_it_6 | 2.36 | 2.31 | 4.49 | 23:55:55Z |
| mockbook_it_7 | 2.11 | 3.79 | 2.81 | 23:55:18Z |
| mockbook_uk_1 | 1.97 | 2.87 | suspended | 23:24:41Z |
| mockbook_sharp | 4.02 | 2.17 | 3.22 | 23:54:04Z |
| mockbook_exchange | 2.89 | 3.30 | 2.44 | 23:53:27Z |
Un esito che il book quota ma adesso non accetta sta in suspended, non in outcomes: «non quotato» e «quotato ma chiuso» restano due fatti distinti.
Decine di concessionari italiani con licenza ADM, più book di riferimento internazionali ed exchange. L'elenco attivo è su /api/v1/bookmakers, con una chiave: nessuna lista di marchi da credere sulla parola.
Campi della risposta di /api/v1/bookmakers: l'endpoint non accetta parametri. Su /api/v1/odds, country e playable_it sono anche filtri.
Su /api/v1/stream arrivano solo i record cambiati e quelli rimossi, niente polling: con state=live il live di solito in 10-30 secondi. Il pre-partita intero oggi non arriva in modo affidabile (un giro completo pesa centinaia di MB): arriva con filtri stretti, a ondate; per tutto il pre-partita usa /odds.
id: mock.42 event: odds data: {"changed":[…],"removed":[]} : ping
GET /api/v1/mock/stream Stream d'esempio, senza chiave · dati sintetici
Non ancora attivo: oggi /odds/history risponde vuoto (history_enabled: false) e la chiamata conta nella quota. Quando lo sarà: una riga ogni volta che un book cambia prezzo, e a partita iniziata la prima riga è la chiusura.
/coverage conta i marchi con una quota valida adesso; /coverage/matrix dice, book per book e sport per sport, quali mercati quotano.
Marchi con una quota valida adesso, per regione · GET /api/v1/coverage
Le variazioni arrivano in POST al tuo URL, firmate HMAC-SHA256; una consegna grande arriva in più pagine numerate.
POST <url> X-Odss-Timestamp: <unix> X-Odss-Signature: t=<unix>,v1=<hex> X-Odss-Page: 1/3 {"page": 1, "pages": 3, "changed": […], "removed": […], "changed_total": <n>, …}
Un agente scopre gli strumenti senza chiave e senza consumare quota; la chiave serve per chiamarli.
| Metodo JSON-RPC | Chiave e quota |
|---|---|
| initialize | no |
| tools/list | no |
| tools/call | sì |
Python e TypeScript senza dipendenze, con paginazione e errori tipizzati. OpenAPI, Postman e llms.txt per chi integra con un agente.
Confronto
Dove ci mettiamo rispetto alle API globali e alla media del mercato. Senza nomi, senza promesse.
| Caratteristica | odss-api | Media del mercato |
|---|---|---|
| Book ADM italiani | Sì, verificabili. /coverage pubblico, /bookmakers con chiave; l'età delle quote che ricevi è misurata e pubblica (p50/p95 su /status). | Pochi, spesso a book. Nate per i book esteri (US/UK/offshore): i concessionari ADM, quando ci sono, sono pochi e spesso pagati a book. |
| Come si paga | Per account. Quota mensile + rate/min: più book o mercati per evento non aumentano il costo. | Per book o a crediti. Crediti mercati×regioni: sul multi-book il costo esplode. |
| Cross-book | Deterministico. Un event_id condiviso da tutti i mercati dell'incontro: confronto nativo, matching non euristico. | Spesso euristico. Quote proprietarie o matching non deterministico. |
| Freschezza | Per book, in chiaro. last_update ISO su ogni book: sai quanto è recente ogni gamba. | Spesso assente. Non esposta per singolo book. |
| Pronta per gli agenti | Sì, standard aperti. OpenAPI 3.1, llms.txt, JSON-LD, /.well-known/api-catalog: un agente la trova e la legge da solo. | Di rado. Docs dietro login o crawler bloccati, nessuno standard agentico. |
| Prezzo e avvio | Listino pubblico. Free tier, Enterprise self-serve configurabile. Chiave in un minuto. | Spesso su trattativa. Enterprise opachi, oppure self-serve con pochi book italiani, spesso pagati a book. |
| Chiavi mirate | Per sport o lega. Es. una chiave «solo calcio», senza limite di numero. | Non documentato. |
Copertura
Non un catalogo: sport, leghe, eventi e book letti in questo momento dall'endpoint pubblico /api/v1/leagues. Cambiano con il palinsesto, e puoi verificarli senza chiave.
Non escludiamo nessuna lega. Seguiamo i principali bookmaker ADM — l'elenco esatto è su /api/v1/bookmakers — e mostriamo tutto ciò che quotano: se un book del feed quota una partita, la vedi anche qui — dalle grandi leghe europee alle serie minori e alle competizioni internazionali. Quello che compare dipende dalla stagione e dal periodo: se non ci sono partite, i bookmaker non le quotano, quindi non appaiono. La lista qui sotto è il palinsesto di questo momento.
Carico il palinsesto…
L'elenco nominativo dei book attivi in questo momento è su GET /api/v1/bookmakers, con i campi country, playable_it, is_exchange e source: richiede una chiave API (la Free si genera in un minuto, senza carta). Senza chiave sono pubblici GET /api/v1/leagues — da cui vengono i conteggi qui sopra — e GET /api/v1/coverage.
Prezzi
Lo streaming SSE arriva con Pro, i webhook con Enterprise. Inizia gratis e disdici quando vuoi.
In tutti i piani, Free compreso:
Per esplorare l'API. Per sempre, senza carta.
0 € per sempre, senza carta
500 richieste/mese · 30/min
Esempio: scrivere e collaudare l'integrazione, anche con il sandbox.
Per progetti personali e piccoli bot.
19 € al mese + IVA
10.000 richieste/mese · 60/min
Esempio: un campionato letto ogni 5 minuti, circa 8.600 richieste al mese.
Per bot e integrazioni in produzione.
79 € al mese + IVA
100.000 richieste/mese · 120/min
Esempio: tre campionati con il live, letti ogni 90 secondi: circa 86.000 richieste al mese.
Per piattaforme e volumi alti.
159 € al mese + IVA
500.000 richieste/mese · 600/min
Esempio: dieci campionati con il live, letti ogni 90 secondi (circa 288.000 richieste al mese), oppure lo stream.
Per piattaforme, aziende e rivenditori: configura volume, rate e licenza — il prezzo si aggiorna da solo e attivi in checkout, senza trattative.
Ti autorizza a mostrare i dati agli utenti finali del tuo prodotto — siti, app, dashboard, widget, comparatori (senza, l'uso resta interno). Non autorizza a creare o commercializzare servizi di surebet/arbitraggio, value betting o piattaforme equivalenti, né a ridistribuire le API o i dati grezzi: per quelli serve una licenza commerciale dedicata. Leggi la licenza
I prezzi indicati sono al netto dell'IVA. L'imposta applicabile viene aggiunta al momento del pagamento in base al tuo paese e al tuo status fiscale: 22% per l'Italia (anche per le imprese con partita IVA italiana); inversione contabile, imposta 0, per le imprese di altri Stati UE con partita IVA valida; operazione fuori campo IVA italiana per i clienti extra-UE. L'importo totale che paghi è quello indicato dal riepilogo del checkout, che confermi prima di inoltrare l'ordine (§4 dei Termini). La quota vale 30 giorni dalla prima richiesta del periodo.
Soluzioni commerciali
Le quote normalizzate sono il primo livello. Se il prodotto che vuoi vendere sono gli arbitraggi, il livello che ti serve è un altro: le surebet già calcolate, con il diritto di rivenderle incluso nell'abbonamento.
Livello 1 · self-serve
Quote e dati normalizzati. Dal piano Free all'Enterprise, prezzo pubblico e attivazione immediata.
Vedi i prezziLivello 2 · piano API
Per chi ci costruisce sopra un prodotto proprio. Non restituisce soltanto le quote: restituisce le surebet già individuate e calcolate dal nostro motore, ricalcolate a ogni ciclo di scansione. Se non devi rivenderle a nessuno non ti serve: ti basta surebett.app.
950 € al mese, al netto dell'IVA · licenza di rivendita inclusa · si disdice in un click dal portale.
I campi elencati sono quelli previsti dove disponibili: la risposta porta ciò che il motore ha davvero calcolato per quell'evento. La licenza di rivendita è inclusa nell'abbonamento: puoi usare le surebet calcolate in un prodotto commerciale tuo, destinato ai tuoi utenti finali, nei limiti dell'uso dichiarato e dei Termini. Non comprende il White Label, che resta un contratto a parte.
Attivazione al pagamento, disdetta in un click dal portale. È un piano a sé e non si somma a un piano a listino: se sull'account ne hai già uno attivo a pagamento, va disdetto prima. Procedendo sottoscrivi la Surebet API Commercial License, nei limiti dell'uso che hai dichiarato qui sopra, e accetti i Termini del servizio (§5).
Livello 3 · a contratto
Per le aziende che non vogliono sviluppare autonomamente la piattaforma: la Surebet completa, fornita come servizio con il tuo marchio.
2.000 € al mese, al netto dell'IVA · attivazione e durata secondo il contratto White Label.
Software, motore e codice sorgente restano di nostra proprietà e vengono concessi in uso secondo il contratto White Label.
La licenza «Redistribuzione Display» dei piani API autorizza a mostrare le quote dentro il tuo prodotto: non autorizza a creare o commercializzare servizi di surebet/arbitraggio, value betting o piattaforme sostanzialmente equivalenti, né a ridistribuire le API o i dati grezzi. Per questi usi servono la Surebet API Commercial License o il contratto White Label — vedi le licenze commerciali e i Termini, §5.
Altre domande? Scrivici a [email protected] o apri un ticket: risponde una persona, via email.
Sì: l'API espone le quote dei concessionari italiani presenti nel feed, filtrabili col parametro bookmakers. L'elenco attivo in questo momento è su GET /api/v1/bookmakers, che richiede una chiave API (la Free si genera in un minuto, senza carta); senza chiave sono pubblici /api/v1/leagues e /api/v1/coverage. Ogni quota porta il suo last_update.
Sì: l'API risponde JSON standard, quindi va dritta in Postgres, SQLite, pandas o Google Sheets. Con gli SDK Python e TypeScript bastano poche righe; il piano Free (500 richieste/mese) è sufficiente per provarci senza carta.
Da noi: Free 500 richieste/mese senza carta, Hobby 19 €/mese + IVA (10.000), Starter 79 €/mese + IVA (100.000), Pro 159 €/mese + IVA (500.000), Enterprise configurabile da 199 € + IVA. Tutti gli importi sono al netto dell'IVA: a un privato italiano si aggiunge il 22%. Per le imprese di altri Stati UE con partita IVA valida si applica l'inversione contabile (imposta 0); per i clienti extra-UE l'operazione è fuori campo IVA italiana. Il totale è sempre indicato nel riepilogo del checkout, che confermi prima dell'ordine (§4 dei Termini). Stessa copertura su tutti i piani: paghi solo il volume.
L'età delle quote che ricevi è misurata, non promessa: p50 e p95 delle ultime 24 ore sono pubblici sulla status page, misurati sullo snapshot servito. Per il push c'è lo streaming SSE; il live in-play ha il suo feed, che si rinnova ogni pochi secondi.
L'uso interno — modelli, bot, analisi, strumenti tuoi — è incluso in tutti i piani. Mostrare i dati agli utenti finali di un tuo prodotto richiede la licenza di Redistribuzione Display (add-on Enterprise): autorizza la sola visualizzazione. Se il prodotto che vuoi vendere sono le surebet — arbitraggio, value betting o servizi equivalenti — serve la Surebet API, un piano a sé da 950 €/mese + IVA, con la licenza per rivenderle inclusa nell'abbonamento e la dichiarazione d'uso obbligatoria: vedi come si attiva. Se non devi rivendere nulla non ti serve: ti basta surebett.app. La piattaforma completa col tuo marchio resta il White Label, a contratto — vedi Surebet API e White Label.
Il motore rilegge i book italiani a ciclo continuo, ma ciò che conta è l'età delle quote che ricevi: la misuriamo sullo snapshot servito e la pubblichiamo sulla status page, con p50 e p95 delle ultime 24 ore (a ottobre 2026: p50 di 11-14 minuti di giorno, circa 18 la sera). Il contenuto italiano del feed si rinnova in media ogni 7-12 minuti, il live ogni pochi secondi. Non devi fidarti sulla parola: ogni quota nella risposta porta il suo last_update.
Il piano Free è per sempre e ha la stessa copertura dei piani a pagamento: così verifichi i dati prima di pagare. Se ti serve più volume per una prova, scrivici a [email protected].
Stesso motore, due prodotti: odss-api vende le quote grezze normalizzate per costruirci sopra; surebett.app è il prodotto finito, con gli arbitraggi già calcolati e gli stake bilanciati.
Per chi sviluppa
Base URL https://odss-api.com. Autenticazione con header x-api-key: odss_live_… oppure Authorization: Bearer. Risposte JSON, quote decimali europee.
Ogni endpoint ha un gemello sotto /api/v1/mock/ che risponde subito, senza registrarti e senza consumare quota: stessa forma della risposta, stessi parametri, stessa validazione stretta del feed vero. I prezzi sono sintetici — mock: true, header X-Odss-Mock: 1, id con prefisso mock_ — servono a scrivere e collaudare il codice, non a giocarci.
curl "https://odss-api.com/api/v1/mock/odds?sport=calcio&limit=3"
Disponibili: /mock/odds · /mock/odds/history · /mock/sports · /mock/bookmakers · /mock/leagues · /mock/status · /mock/stream (SSE) · /mock/ticker (un frame di quote 1X2 d'esempio ogni 5 s, senza parametri). Il parametro seed rende la risposta riproducibile: usalo nella CI invece di bruciare quota a ogni run.
Sul feed VERO sono pubblici senza chiave anche /api/v1/leagues, /api/v1/coverage, /api/v1/status e /api/v1/pulse.
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: [...] }
Le quote cross-book correnti, raggruppate per evento, mercato e linea. Ogni record elenca i bookmaker con i loro esiti e il timestamp dell'ultimo aggiornamento.
| Parametro | Descrizione |
|---|---|
| sport string | Filtro esatto sullo sport (es. calcio, tennis, basket). Valori: vedi /api/v1/sports. |
| market string | Mercato canonico: 1x2, ou, btts, dc, ah (handicap asiatico), eh (handicap europeo), moneyline… |
| bookmakers string | Lista CSV di chiavi book (es. snai,bet365). Valori: vedi /api/v1/bookmakers. |
| league string | Filtro per sottostringa, case-insensitive (es. serie a). Valori: vedi /api/v1/leagues. |
| event_id string | Un solo evento, per id esatto. |
| state prematch | live | all | prematch (default), live (in-play, con punteggio e minuto) o all (entrambi). Con live, se il motore in-play è spento la lista è vuota e live_enabled=false. Se la chiave ha un ambito di feed (solo prematch o solo live), uno state fuori ambito risponde 403 e all degrada allo stato permesso. |
| limit integer | Record per pagina. Default 500, max 5000. |
| offset integer | Indice di partenza per la paginazione. Default 0. |
| content match | player | all | match = solo righe di incontro; player = solo player props; all (default) = entrambi. I props sono inclusi in ogni piano: il parametro restringe la risposta, non sblocca nulla. |
| player string | Sottostringa del nome del giocatore, senza distinzione di maiuscole; implica content=player. |
| commence_from · commence_to date-time | Finestra sull'inizio dell'evento (ISO 8601), estremi inclusi. Con una finestra i record senza commence_time sono esclusi; una data illeggibile, o from dopo to, è un 400. |
| playable_it boolean | true = in ogni record solo i book giocabili dall'Italia (concessione ADM); false = solo gli altri. I record rimasti senza book vengono tolti. |
| country string | CSV di paesi di licenza (ISO 3166-1 alpha-2, oppure world): in ogni record restano solo quei book, es. IT oppure GB,SE. |
| after string | Paginazione STABILE a cursore: after= vuoto per la prima pagina, poi il next_after della risposta finché è null. L'ordine non dipende dall'aggiornamento dello snapshot, quindi una sincronizzazione completa non ha buchi né doppioni. Alternativo a offset; si combina con changed_since. |
| format full | compact | compact = gli stessi dati senza ripetizioni (i metadati dei book una volta in books, i dati dell'evento una volta in events): circa il 40% di byte in meno. Default full, lo schema di sempre. |
| changed_since string | Sincronizzazione DELTA, su ogni piano. La prima volta changed_since= vuoto: risposta completa più un delta_token. Poi rimanda il token: solo i record cambiati o comparsi (in odds, nello stato attuale) e quelli spariti (in removed), con un nuovo delta_token. Un token vecchio (oltre circa 10 minuti) o di un altro avvio del server risponde 410 resync_required: si riparte con changed_since= vuoto. A prezzo invariato un record non torna nel delta: il suo last_update resta quello dell'ultimo cambio, anche se il book è stato riletto dopo. |
| Campo | Descrizione |
|---|---|
| count | Totale record che soddisfano i filtri (su tutte le pagine). |
| offset · returned | Eco dell'offset richiesto e record effettivamente restituiti in questa pagina. |
| odds[].event_id | Id deterministico dell'evento: identico per tutti i mercati dello stesso incontro e stabile per l'intera finestra prematch. |
| odds[].event | Nome normalizzato dell'evento (Casa - Ospite). |
| odds[].sport · league | Sport e lega/competizione dell'evento. |
| odds[].home_team · away_team | Le due squadre, quando disponibili. |
| odds[].commence_time | Inizio dell'evento, ISO 8601 UTC. |
| odds[].market · line · scope · period | Mercato canonico, eventuale linea (es. 2.5), ambito (es. squadra) e periodo (es. 1° tempo). |
| odds[].state · score · minute | state = prematch o live. Per il live: score (es. «1-0») e minute (es. «63'») correnti. Stesso event_id del prematch per correlare la stessa partita nei due stati. |
| …bookmakers[].key | Chiave del bookmaker, con country, playable_it e is_exchange. |
| …bookmakers[].outcomes | Mappa esito → quota decimale (es. HOME: 2.10). |
| …bookmakers[].suspended | Esiti che quel book quota ma su cui ora non accetta giocate. Non stanno in outcomes (un esito sospeso non ha un prezzo giocabile) ma sono nominati qui, così «questo book non quota l'esito» e «lo quota ed è chiuso adesso» restano due fatti distinti. Campo opzionale, e l'assenza vuol dire qualcosa: se manca, quel book non dichiara lo stato; [] vuol dire dichiarata, e niente di sospeso. Non leggere l'assenza come lista vuota. |
| …bookmakers[].last_update | Timestamp ISO dell'ultimo aggiornamento riuscito delle quote di quel book. |
| …bookmakers[].family | Piattaforma da cui arriva il listino. Marchi della stessa famiglia possono servire lo STESSO listino: contarli come listini indipendenti inventa arbitraggi che non esistono. Stessa famiglia non vuol dire sempre stesso prezzo: è un avviso di correlazione, non una regola di esclusione. |
| odds[].player · player_id | Solo nelle righe dei player props (assenti, non null, nelle righe di incontro): player fa parte dell'identità della riga; player_id è l'id stabile del giocatore per quel book, per seguirlo da un aggiornamento all'altro (non è un id valido tra book diversi). |
Ripeti la chiamata aumentando offset di returned, finché offset + returned < count. Il palinsesto è vivo: count può variare leggermente tra le pagine.
GET /api/v1/odds?sport=calcio&limit=1000&offset=0
GET /api/v1/odds?sport=calcio&limit=1000&offset=1000
# … finché offset + returned < count
Gli sport disponibili in questo momento nel feed (i valori del parametro sport).
I bookmaker attivi nel feed, ognuno con questi campi.
| Campo | Descrizione |
|---|---|
| country | Codice ISO 3166-1 alpha-2 del paese di licenza (IT, GB, US, SE…), oppure world quando non è attribuito. |
| playable_it | true solo per i book con concessione ADM, cioè giocabili dall'Italia; false per tutti gli altri book del feed, dalle sharp di riferimento come Pinnacle ai marchi esteri. |
| is_exchange | Exchange, con commissione sulla vincita. |
| feed_keys | Le chiavi con cui le quote di questo operatore escono in /odds: il marchio e, se c'è, la sua corsia di mercato dedicata (es. <marchio>-corners). Un operatore è una riga sola. |
| derived_from | Solo se le quote pre-partita dell'operatore sono copiate da un altro: la chiave del book d'origine, come derived_from su ogni quota (derived_states dice in quale stato). |
| source | Tipo di canale del listino: direct | partner_feed. |
Il palinsesto corrente aggregato: per ogni sport le leghe quotate, con numero di eventi e di bookmaker. Utile per scoprire i valori del filtro league.
Server-Sent Events: arrivano solo i record cambiati e quelli rimossi, niente polling. Con state=live il live arriva di solito in 10-30 secondi (mediana misurata circa 15 s). Limite di oggi, misurato l'8 ottobre 2026: con state=all un giro pre-partita completo pesa centinaia di MB e la connessione cade prima di riceverlo; lo stream è rimasto senza variazioni il 79% del tempo, con un resync ogni 12 minuti circa. Il pre-partita arriva solo con filtri stretti (sport, mercato, lega), a ondate, quando si rinnova lo snapshot servito. Stiamo riscrivendo la consegna a pagine piccole con contropressione; fino ad allora, per tutto il pre-partita usa lo snapshot paginato di /odds.
| Voce | Descrizione |
|---|---|
| hello | Alla connessione. |
| odds | I record CAMBIATI (stesso schema di /odds, ognuno col suo state) e i rimossi. |
| sport · state | Parametri opzionali (state: prematch | live | all). Snapshot iniziale via GET /odds?state=…. |
| Cadenza | Quella dello snapshot servito: il live si rinnova ogni pochi secondi, il pre-partita in media ogni 4-6 minuti (il contenuto italiano ogni 7-12). Fa fede last_update, con un limite: a prezzo invariato il record non viene rimandato, quindi il last_update che hai resta quello dell'ultimo cambio anche se il book è stato riletto dopo. L'età vera del pre-partita servito è su /status (served_age). |
| Limiti | Max 3 stream concorrenti; la connessione conta 1 richiesta di quota. |
Non ancora attivo. Oggi la cattura è spenta: ogni chiamata risponde 200 con count: 0 e history_enabled: false, e conta nella quota. Quando sarà attivo: storico delle variazioni di quota per un evento, una riga ogni volta che un bookmaker cambia prezzo su un gruppo. Filtri event_id (obbligatorio), book, market, from/to (ISO), limit. Ordine dal più recente: la prima riga di un evento iniziato è la sua chiusura. Rispetta l'ambito della chiave.
curl "https://odss-api.com/api/v1/odds/history?event_id=a3f9c1e07b2d4865&book=snai" \
-H "x-api-key: odss_live_..."
Middle Over/Under calcolati dal feed corrente: OVER su una linea bassa da un book, UNDER su una linea alta da un altro. Se il totale cade nella finestra vincono entrambe le giocate. Campi middle_window, hit_return_pct, miss_return_pct, safe (nessuna perdita nemmeno a vuoto). Filtri: sport, min_return, safe, limit.
Regola di freschezza: una quota ferma da più di stale_after_seconds (900s di default) resta nelle risposte di /odds col suo last_update, ma non viene accoppiata in un middle: una gamba vecchia probabilmente non esiste più sul sito del bookmaker. La soglia applicata e il numero di gambe scartate sono nella risposta.
Limiti di safe, oggi: alcune famiglie di mercato non sono ancora separate per unità (nel tennis e nel volley un totale di set può finire accanto a un totale di game o di punti), alcuni pseudo-eventi «Home - Away» di una piattaforma sono serviti come partite, e due partite omonime possono condividere un event_id. In questi casi safe: true non è un middle vero: prima di agire controlla che le due gambe siano la stessa partita, la stessa unità e lo stesso orario. La risposta lo ricorda nel campo safe_note.
curl "https://odss-api.com/api/v1/middles?sport=calcio&safe=true" \
-H "x-api-key: odss_live_..."
Quanti marchi di bookmaker hanno una quota valida nel feed di questo momento, per regione (Italia, USA, UK, mondo). Coincide con le voci di /api/v1/bookmakers: entrambi contano un operatore una volta sola, con le corsie di mercato dedicate (es. <marchio>-corners) sotto il marchio; in /bookmakers le chiavi con cui le sue quote escono stanno in feed_keys.
Per ogni bookmaker, sport per sport: i mercati normalizzati che quota adesso, con le linee viste. Serve a distinguere tre cose che un elenco piatto confonde.
Un mercato non elencato sotto un operatore attivo è un'assenza strutturale: non lo quota, e domani sarà uguale. Gli operatori in live_only_bookmakers hanno righe ma non nel prematch, quindi sui loro mercati prematch la risposta non dice nulla; se una corsia del feed non ha risposto, incomplete_lanes la nomina e la copertura è parziale, non assente.
E un mercato che il motore non sa mappare con certezza non viene indovinato: esce come other:<etichetta> e qui viene solo contato (other_markets), perché due book lo chiamano in modi diversi e confrontare quelle etichette sarebbe sbagliato — quelle che molti book scrivono uguale stanno in other_markets_common. Ambito prematch, ricalcolata al massimo ogni 10 minuti (generated_at).
Il battito del feed, solo numeri aggregati (niente prezzi, niente nomi di book): è ciò che interrogano da sole le pagine di questo sito. Nessun parametro, Cache-Control: public, max-age=5, limite per IP a sé (60 al minuto).
| Campo | Descrizione |
|---|---|
| prematch_it_at | L'istante in cui è stato pubblicato lo snapshot che contiene la corsia italiana attuale: mai più nuovo delle pagine servite. |
| beats | Gli ultimi ingressi di una corsia italiana nuova nello snapshot servito, fino a 30, raccolti dall'avvio del server (beats_since). |
| freshness_24h | Per ogni mezz'ora delle ultime 24 ore: served_p50 e served_p95, l'età delle quote italiane che ricevevi (campionata ogni 2 minuti sullo snapshot servito), e p50/p95, l'età dentro il motore. In served gli stessi percentili sulle 24 ore. Una mezz'ora senza campioni resta vuota, mai stimata. |
Server MCP (JSON-RPC 2.0) per agenti AI e connettori (Claude, ChatGPT…). Autenticazione con la stessa chiave (Authorization: Bearer odss_live_… o x-api-key). Tool: get_odds (con state=live), list_sports, list_bookmakers, list_leagues. Solo tools/call consuma quota; l'handshake è gratis. Stateless: ogni richiesta è autosufficiente.
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}}}'
Registra una URL https e ricevi le variazioni di quota via POST, con lo stesso payload {changed, removed} dello stream.
| Voce | Descrizione |
|---|---|
| POST /api/account/webhooks | Dalla dashboard o via API, con la sessione account. Body {url, sport?, state?}; il secret è mostrato una volta, max 20 per account. |
| X-Odss-Signature | t=<unix>,v1=<hex> = HMAC-SHA256 di «{timestamp}.{body}» col secret del webhook. Ogni consegna è firmata: verifica la firma, rifiuta i timestamp vecchi. |
| X-Odss-Page | pagina/totale: una consegna può arrivare in più POST consecutivi, ognuno firmato per conto suo. Ogni corpo porta page, pages, changed_total e removed_total, così dalla prima pagina sai già quanto sta arrivando. |
| Regole | Rispondi 2xx. Solo https, niente redirect seguiti; gli endpoint che falliscono a ripetizione si auto-disabilitano. Non limitare la frequenza dell'endpoint: una pagina rifiutata ferma le successive. |
Ogni risposta autenticata include X-RateLimit-Limit (quota mensile del piano), X-RateLimit-Remaining e X-RateLimit-Reset (unix time in secondi in cui la finestra si riapre; sul 429 da quota la stessa data è nel corpo come retry_at). La quota vale per una finestra di 30 giorni che parte dalla prima richiesta del periodo: alla scadenza il contatore si azzera e riparte con la richiesta successiva.
| Codice | Descrizione |
|---|---|
| 400 | Richiesta non valida: parametro sconosciuto, valore fuori da quelli ammessi (es. state) o parametro obbligatorio mancante (es. event_id su /odds/history). Il corpo della risposta dice quale. |
| 401 | Chiave mancante, non valida o revocata. |
| 403 | Fuori ambito: account sospeso, feed fuori dallo scope della chiave (es. live con chiave solo-prematch) o funzione riservata al piano (stream: Pro ed Enterprise; webhook: Enterprise). |
| 429 | Burst: superate le richieste al minuto del piano. Header Retry-After: 60. |
| 429 | Quota mensile esaurita: passa a un piano superiore o attendi la finestra. |
| 502 | Feed momentaneamente non disponibile: riprova con backoff. |
Su tutti gli endpoint /api/v1 un parametro che non riconosciamo non viene mai ignorato: se scrivi bookmaker invece di bookmakers ricevi 400 con il nome sbagliato, l'elenco di quelli ammessi su quell'endpoint e, se è un refuso, il suggerimento del nome giusto. Il confronto è esatto: anche Sport con la maiuscola viene rifiutato. Gli endpoint di catalogo (/sports, /bookmakers, /leagues, /coverage, /status) non accettano alcun parametro. Preferiamo un errore subito a una risposta 200 con dati non filtrati che sembrano corretti: il 400 è deterministico, va corretto e non ritentato, e non consuma quota.
La stessa regola vale per gli argomenti dei tool del server MCP (POST /api/mcp): un nome che non esiste, o un tipo sbagliato come una lista al posto della stringa CSV, riceve un errore JSON-RPC -32602 invece di essere ignorato. Il campo error.data porta i nomi ammessi, così l'agente si corregge da solo.
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: after, bookmakers, changed_since, commence_from, commence_to, content, country, event_id, format, league, limit, market, offset, playable_it, player, sport, state"
}
Per generare client, SDK o usare l'API da un agente AI: il contratto OpenAPI 3.1 e una guida sintetica per LLM sono pubblici e sempre allineati.
| Risorsa | Descrizione |
|---|---|
| /openapi.json | Contratto OpenAPI 3.1 (endpoint, parametri, schemi, auth x-api-key). |
| /llms.txt | Guida markdown per LLM (llmstxt.org): riassunto e link alle risorse. |
| /postman_collection.json | Collezione Postman: importala e imposta la variabile x-api-key per provare subito gli endpoint. |
| /sdk/odss_api.py | SDK Python ufficiale (single-file, zero dipendenze): client tipizzato con paginazione automatica e supporto live. |
| /sdk/odss-api.ts | SDK TypeScript ufficiale (single-file, zero dipendenze): tipi, iteratore async e helper per lo stream SSE. |
| /.well-known/api-catalog | Catalogo API (RFC 9727, linkset JSON). |
L'uso interno (modelli, bot, analisi, backtest) è incluso in tutti i piani. La ridistribuzione dei dati — ad esempio mostrarli agli utenti finali di un tuo prodotto — richiede la licenza di Redistribuzione Display (add-on Enterprise, +€120/mese), che copre la sola visualizzazione. Creare, alimentare o commercializzare servizi di surebet/arbitraggio, di value betting o equivalenti richiede invece la Surebet API, il piano che include la licenza per rivendere le surebet calcolate: 950 €/mese + IVA. Ridistribuire le API o i dati grezzi resta fuori da ogni piano: per quello scrivici a [email protected].
Quando sei pronto, la chiave Free si crea in un minuto. Senza carta.
curl https://odss-api.com/api/v1/mock/odds