Italy Odds API: Merge 14 Italian Books Into 9 Serie A Feeds

Italy Odds API
How To Guides November 11, 2026

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.