Italy Odds API: Merge 14 Italian Books Into 9 Serie A Feeds
An Italian odds API should return the books Italian bettors use: Sisal, Snai, Eurobet, Goldbet, Lottomatica, bet365 and the rest of the ADM-licensed market. OddsPapi carries 14 of them on one key, next to Pinnacle and 300+ other bookmakers. On 4 November 2026 every Serie A fixture of the coming round held 272 to 275 books, and 13 or 14 of them were Italian books with a live 1X2 price.
On the same ten boards, those 14 slugs quoted 7 to 9 distinct 1X2 prices, because two groups of brands share one price feed each. This guide shows you how to pull the Italian board, merge the brands that share a price, and rebuild each book’s Serie A close from free price history. At the close of the last round, AdmiralBet Italy was the tightest Italian book, at a median 3.88% against Pinnacle’s 2.58%.
Why Italian odds are hard to collect
Italian sportsbooks build their .it sites for bettors, not for code. So most Italian projects scrape: one scraper per site, one page layout per scraper, and a fix every time a site changes its event page.
Scraping also hides the shared feeds. Sisal, Snai and PokerStars Italy showed the same 1X2 on all 10 Serie A boards of the round. Goldbet, Lottomatica, BetFlag and Planetwin365 showed the same 1X2 on every board where all four priced. If you scrape all seven sites, you maintain seven scrapers to collect two prices.
| Scraping Italian sites | OddsPapi | |
|---|---|---|
| Access | One scraper per site | One key, the apiKey query parameter |
| Books per Serie A fixture | The sites you maintain scrapers for | 272 to 275 books, 13 or 14 Italian books on the 1X2 (4 Nov 2026) |
| Shared feeds | Hidden until you compare the prices yourself | cloneOf names the parent feed on every Italian skin |
| Price history | You record it yourself, from the day you start | /v4/historical-odds, free on every plan |
| Live updates | Poll each site | Poll /v4/odds, or take the WebSocket feed |
Step 1: Check the Italian slugs
Every request carries the key as a query parameter. The snippets import this helper, which waits out a 429 (the body carries retryMs) and retries a 5xx:
import os
import time
import requests
API_KEY = os.environ["ODDSPAPI_API_KEY"]
BASE = "https://api.oddspapi.io/v4"
def get(path, **params):
"""GET with the key on the query string; waits out a 429 or a 5xx and retries."""
params["apiKey"] = API_KEY
for _ in range(5):
r = requests.get(f"{BASE}{path}", params=params, timeout=30)
if r.status_code == 429:
time.sleep(r.json()["error"].get("retryMs", 1000) / 1000 + 0.2)
elif r.status_code >= 500:
time.sleep(2)
else:
return r
return r
Start from the catalogue, because a wrong slug fails in a filter. Every Italian slug ends in .it. The list below is the set this guide uses:
from common import get
IT_BOOKS = ["bet365.it", "eurobet.it", "sisal.it", "snai.it", "goldbet.it", "lottomatica.it",
"betflag.it", "planetwin365.it", "admiralbet.it", "quigioco.it", "netbet.it",
"888sport.it", "pokerstars.it", "leovegas.it"]
if __name__ == "__main__":
catalogue = {b["slug"]: b for b in get("/bookmakers").json()}
print(f"{len(catalogue)} bookmakers in the catalogue")
for slug in IT_BOOKS:
b = catalogue.get(slug)
if b is None:
print(f"{slug:16} not in catalogue")
continue
print(f"{slug:16} {b['bookmakerName']:16} liveOdds={b['liveOdds']!s:5} cloneOf={b['cloneOf']}")
370 bookmakers in the catalogue
bet365.it bet365 IT liveOdds=False cloneOf=None
eurobet.it Eurobet IT liveOdds=True cloneOf=None
sisal.it Sisal IT liveOdds=True cloneOf=None
snai.it Snai IT liveOdds=True cloneOf=sisal.it
goldbet.it Goldbet IT liveOdds=True cloneOf=None
lottomatica.it Lottomatica IT liveOdds=True cloneOf=goldbet.it
betflag.it BetFlag IT liveOdds=True cloneOf=goldbet.it
planetwin365.it Planetwin365 IT liveOdds=True cloneOf=goldbet.it
admiralbet.it AdmiralBet IT liveOdds=True cloneOf=None
quigioco.it Quigioco IT liveOdds=True cloneOf=None
netbet.it NetBet IT liveOdds=True cloneOf=None
888sport.it 888Sport IT liveOdds=True cloneOf=None
pokerstars.it PokerStars IT liveOdds=True cloneOf=sisal.it
leovegas.it LeoVegas IT liveOdds=True cloneOf=None
Read cloneOf first. On most of the catalogue it does not predict a shared price: in the UK odds API guide, Unibet and Casumo read cloneOf: None and still quoted identical prices. On the Italian books the flag held. Snai and PokerStars point to sisal.it, and Lottomatica, BetFlag and Planetwin365 point to goldbet.it, and the prices in Step 2 match those groups. Check the prices anyway, because the flag can change in the next catalogue update.
liveOdds says whether the book streams in-play prices. bet365.it reads False but quotes pre-match.
Step 2: Pull the Serie A board and merge the shared prices
Ask /v4/fixtures for Serie A (tournamentId=23), then pull the whole board for one fixture in one call. The script keeps the Italian books, reads market 101 (the full-time 1X2), and groups the books by their price tuple:
import time
from collections import defaultdict
from common import get
from step1_catalogue import IT_BOOKS
fixtures = get("/fixtures", sportId=10, tournamentId=23,
**{"from": "2026-11-08", "to": "2026-11-09"}).json()
fixture = next(f for f in fixtures if f["participant1Name"] == "SSC Napoli")
print(fixture["participant1Name"], "v", fixture["participant2Name"], fixture["startTime"])
time.sleep(1.0)
board = get("/odds", fixtureId=fixture["fixtureId"]).json()["bookmakerOdds"]
print(f"{len(board)} books on the board")
feeds = defaultdict(list) # price tuple -> slugs quoting it
for slug in IT_BOOKS:
book = board.get(slug, {})
if book.get("suspended") or book.get("bookmakerIsActive") is False:
continue # the whole book is parked
market = book.get("markets", {}).get("101") # 1X2, full time
if not market:
continue
legs = [market["outcomes"].get(o, {}).get("players", {}).get("0", {}) for o in ("101", "102", "103")]
if all(leg.get("active") is not False and leg.get("price") for leg in legs):
feeds[tuple(leg["price"] for leg in legs)].append(slug)
print(f"{sum(len(s) for s in feeds.values())} Italian books priced the 1X2, {len(feeds)} distinct prices")
for prices, slugs in sorted(feeds.items(), key=lambda kv: sum(1 / p for p in kv[0])):
margin = (sum(1 / p for p in prices) - 1) * 100
print(f"{margin:5.2f}% {prices} {', '.join(slugs)}")
SSC Napoli v Lazio Rome 2026-11-08T11:30:00.000Z
272 books on the board
13 Italian books priced the 1X2, 8 distinct prices
4.60% (2.2, 3.65, 3.15) netbet.it
5.47% (2.22, 3.55, 3.1) quigioco.it
5.64% (2.2, 3.65, 3.05) eurobet.it
6.02% (2.2, 3.6, 3.05) goldbet.it, lottomatica.it, betflag.it, planetwin365.it
6.41% (2.2, 3.55, 3.05) admiralbet.it
7.36% (2.2, 3.5, 3.0) sisal.it, snai.it, pokerstars.it
8.54% (2.05, 3.45, 3.25) 888sport.it
11.60% (2.0, 3.35, 3.15) leovegas.it
Thirteen Italian books gave eight distinct prices on Napoli v Lazio. Across the ten fixtures of the round, the Italian books priced the 1X2 on 9 to 14 slugs and gave 7 to 9 distinct prices. Count each price group once before you average Italian prices, or the Goldbet group outvotes the independent books four to one.
The book-level flags also move. On the first pull of the round (4 November, 09:18 UTC), Goldbet, Lottomatica, BetFlag and Planetwin365 shipped bookmakerIsActive: false on Napoli v Lazio and priced the other nine fixtures. Minutes later the group was back on that board. Check the book-level flags on every pull, before the price-level active flag.
On the live board NetBet Italy was the tightest Italian book (median 1X2 margin 5.01% over the ten fixtures), then bet365.it (5.03%, four boards), Eurobet (5.80%) and AdmiralBet (6.11%). LeoVegas Italy sat at 10.5% to 12.1%. Pinnacle’s median on the same boards was 3.24%.
Step 3: Rebuild the Italian close from free history
The live board shows where the Italian books sit three days out. The close shows where they sit when the market knows the most. /v4/historical-odds returns every price each book posted on a played fixture, up to three books per call. Pass outcomeId to keep the payload small.
The script below queries one slug per price group. It takes each book’s last price before the scheduled kick-off, drops a price that the book stopped quoting more than 30 minutes before kick-off, then takes the best Italian price on each leg:
import time
from datetime import datetime, timedelta
from common import get
FIXTURE_ID = "id1000002371945376" # Lazio v Cagliari, played 1 Nov 2026
# one slug per price family: sisal.it stands for snai.it and pokerstars.it,
# goldbet.it for lottomatica.it, betflag.it and planetwin365.it
IT = ["admiralbet.it", "netbet.it", "goldbet.it", "quigioco.it", "eurobet.it", "sisal.it",
"bet365.it", "888sport.it", "leovegas.it"]
BOOKS = ["pinnacle"] + IT
FRESH = timedelta(minutes=30) # drop a price the book stopped quoting long before kick-off
LEGS = ("101", "102", "103") # home, draw, away on market 101 (1X2)
def ts(s):
return datetime.fromisoformat(s.replace("Z", "+00:00"))
fixture = get("/fixture", fixtureId=FIXTURE_ID).json()
kickoff = ts(fixture["startTime"])
print(fixture["participant1Name"], "v", fixture["participant2Name"], "kick-off", kickoff)
close = {b: {} for b in BOOKS}
for i in range(0, len(BOOKS), 3): # /historical-odds takes up to 3 slugs per call
group = BOOKS[i:i + 3]
for leg in LEGS:
time.sleep(4.6)
data = get("/historical-odds", fixtureId=FIXTURE_ID,
bookmakers=",".join(group), outcomeId=leg).json()
for book in group:
snaps = (data.get("bookmakers", {}).get(book, {}).get("markets", {})
.get("101", {}).get("outcomes", {}).get(leg, {})
.get("players", {}).get("0", []))
before = [s for s in snaps if ts(s["createdAt"]) < kickoff]
last = max(before, key=lambda s: s["createdAt"]) if before else None
if last and last["active"] and kickoff - ts(last["createdAt"]) <= FRESH:
close[book][leg] = last["price"]
def margin(prices):
return (sum(1 / p for p in prices) - 1) * 100
for book in BOOKS:
if len(close[book]) == 3:
print(f"{book:14} close {[close[book][l] for l in LEGS]} margin {margin(close[book].values()):.2f}%")
best = []
for leg in LEGS:
quotes = {b: close[b][leg] for b in IT if leg in close[b]}
top = max(quotes.values())
best.append(top)
print(f"leg {leg}: best {top:<5} from {', '.join(b for b, p in quotes.items() if p == top)}")
print(f"best Italian price per leg: margin {margin(best):.2f}%")
Lazio Rome v Cagliari Calcio kick-off 2026-11-01 14:00:00+00:00
pinnacle close [1.505, 4.52, 6.83] margin 3.21%
admiralbet.it close [1.52, 4.55, 6.2] margin 3.90%
netbet.it close [1.52, 4.45, 6.0] margin 4.93%
eurobet.it close [1.5, 4.3, 6.4] margin 5.55%
888sport.it close [1.47, 4.2, 6.5] margin 7.22%
leovegas.it close [1.41, 3.95, 6.1] margin 12.63%
leg 101: best 1.52 from admiralbet.it, netbet.it
leg 102: best 4.55 from admiralbet.it
leg 103: best 7.0 from sisal.it
best Italian price per leg: margin 2.05%
On Lazio v Cagliari the best Italian price per leg closed at 2.05%, tighter than Pinnacle’s 3.21%. AdmiralBet supplied two legs and Sisal the third. Sisal’s home and draw prices failed the freshness filter, so only its away price counts.
We ran the same cut on all ten Serie A fixtures played 31 October to 2 November 2026. Pinnacle closed at a median 2.58% (2.49% to 3.21%). The best Italian price per leg closed at a median 2.91% (2.05% to 3.91%). It was tighter than Pinnacle on 4 of 10 fixtures, and it matched or beat Pinnacle’s price on 18 of 30 legs. AdmiralBet supplied the best Italian price on 17 legs, Sisal on 8, bet365.it on 7 and the Goldbet group on 4.
Each Italian book’s own close, with the same cut and the same 30-minute freshness filter:
| Book | Slug | Fixtures with a fresh close | Median 1X2 margin at the close | Median days open before kick-off | Median home-price changes |
|---|---|---|---|---|---|
| Pinnacle (reference) | pinnacle |
10 of 10 | 2.58% | 6.7 | 107 |
| AdmiralBet Italy | admiralbet.it |
9 of 10 | 3.88% | 4.1 | 46 |
| NetBet Italy | netbet.it |
8 of 10 | 5.05% | 6.9 | 60.5 |
| Goldbet (also Lottomatica, BetFlag) | goldbet.it |
3 of 10 | 5.18% | 4.2 | 10.5 |
| Quigioco | quigioco.it |
5 of 10 | 5.62% | 4.2 | 48 |
| bet365 Italy | bet365.it |
3 of 10 | 5.80% | 6.9 | 18 |
| Eurobet | eurobet.it |
5 of 10 | 6.41% | 4.6 | 19 |
| Sisal | sisal.it |
5 of 10 | 6.52% | 4.2 | 13.5 |
| 888sport Italy | 888sport.it |
6 of 10 | 6.53% | 6.2 | 18.5 |
| LeoVegas Italy | leovegas.it |
8 of 10 | 11.51% | 6.2 | 15.5 |
AdmiralBet Italy closed at 3.40% to 4.16% on nine fixtures, about 1.3 points above Pinnacle and 1.2 points under the next Italian book. It also moves: a median 46 home-price changes per fixture, against 10.5 for the Goldbet group and 13.5 for Sisal. If you need one Italian book as a reference price, start with AdmiralBet, and rank the rest per fixture.
The freshness column matters as much as the margin. The Goldbet group and bet365.it had a fresh price on all three legs at only 3 of 10 closes, because they change their prices less often than once every 30 minutes near kick-off. If you widen the filter, their stale prices enter the close. If you narrow it, more books drop out. Pick the window to suit your model, and report it next to every number.
The historical odds API guide compares the scheduled kick-off, the recorded kick-off and the last active row as cut points. To turn the merged Italian board into a fair price, the consensus odds guide de-vigs a deduplicated board. The Serie A odds API guide covers the rest of the Serie A menu, and the line shopping guide runs the best-price logic live.
Italian odds API FAQ
Is there an Italian odds API?
Yes. OddsPapi returns Italian bookmaker odds as JSON on /v4/odds, including Sisal, Snai, Eurobet, Goldbet, Lottomatica, bet365 Italy, AdmiralBet and NetBet Italy. On 4 November 2026 each Serie A fixture carried 13 or 14 Italian books with a 1X2 price, out of 272 to 275 books on the board.
Which Italian bookmakers does the API cover?
Check /v4/bookmakers for the current list. The Italian set in this guide is bet365.it, eurobet.it, sisal.it, snai.it, goldbet.it, lottomatica.it, betflag.it, planetwin365.it, admiralbet.it, quigioco.it, netbet.it, 888sport.it, pokerstars.it and leovegas.it.
Do Sisal and Snai share odds?
Yes, on Serie A. Sisal, Snai and PokerStars Italy quoted the same 1X2 on all 10 boards of the 6 to 8 November round, and the catalogue marks snai.it and pokerstars.it as cloneOf sisal.it. Goldbet, Lottomatica, BetFlag and Planetwin365 form a second group under goldbet.it.
Which Italian bookmaker has the best Serie A odds?
At the close of 10 Serie A fixtures played 31 October to 2 November 2026, AdmiralBet Italy had the tightest Italian 1X2 margin (median 3.88%) and supplied the best Italian price on 17 of 30 legs. Combined, the best Italian price per leg closed at a median 2.91%.
Can I get historical Italian bookmaker odds?
Yes. /v4/historical-odds returns every price a book posted on a played fixture, up to three bookmakers per call, on every plan. Pass outcomeId to keep each response small.
Pull the Italian board on one key
Every call in this guide runs on the free key: 14 Italian slugs on each Serie A board, 300+ bookmakers in all, free price history for the close, and a WebSocket feed when polling is too slow. The Serie A odds page shows the live board. Get a free API key and run Step 2 on this weekend’s fixtures.