1xBet API: Which of 8 Feeds Quotes the Tighter Line?

1xBet API
How To Guides October 15, 2026

If you searched for a 1xBet API, you want 1xBet’s lines as JSON, next to the books you already price against. OddsPapi carries the book under the 1xbet slug, in the same schema as Pinnacle and 350+ other bookmakers. One call returns it. Read it with care, because 1xbet is one of eight slugs on our board that carry the same 1xBet event ID.

The other seven link to 22bet.com: 22bet, 1xbit, betwinner, fairpari, megapari, melbet and spelet.lv. Those seven quote byte-identical prices. 1xbet runs a second price book on the same event, and on 19 live boards (7 October 2026) it priced the main line at a 4.16% median margin against 5.40% on 22bet. By the close the gap narrows: on 54 played fixtures the two books closed identical on 19. The 22bet line carries the bigger menu. This guide shows you how to find the eight slugs, collapse them to two price books, and decide which one to read for each market.

Why a 1xBet scraper gives you one feed out of eight

A scraper pointed at one 1xBet site gives you one price book and one site’s HTML to maintain. It does not tell you that seven more slugs carry the same event, or that two of the eight price it differently. If you add all eight to a consensus, one price counts seven times. Our consensus odds guide covers why that skews a fair-value line.

OddsPapi gives every book a bookmakerFixtureId, the event ID from the bookmaker’s own site, and a fixturePath deep link. Those two fields group the eight slugs for you. We used the same method for the Kambi feeds in the Unibet API guide and for Bwin’s regional sites in the Bwin API guide.

Scrape one 1xBet site OddsPapi 1xbet and 22bet
Feeds The one site you scrape 8 slugs on one event ID, plus 350+ other books in the same call
Duplicate detection You match events across sites yourself bookmakerFixtureId and fixturePath on every book
Schema The site’s own markup One JSON shape for every book, with native market IDs for spreads, totals and props
Played fixtures Only what your recorder saved /v4/historical-odds on the free tier
Live updates Your polling loop REST or WebSocket

Step 1: find the 1xBet slugs in the catalogue

Authentication is one query parameter, apiKey. The helper waits out a 429 for as long as the error body says, backs off on a 5xx, and returns None on a 404.

import os, time, requests
from datetime import datetime, timedelta, timezone
from statistics import median

API_KEY = os.environ["ODDSPAPI_API_KEY"]
BASE = "https://api.oddspapi.io/v4"

def get(path, **params):
    params["apiKey"] = API_KEY
    for _ in range(8):
        r = requests.get(f"{BASE}/{path}", params=params, timeout=180)
        if r.status_code == 429:                      # rate limited: wait as told
            time.sleep(r.json().get("error", {}).get("retryMs", 2000) / 1000 + 0.5)
            continue
        if r.status_code >= 500:                      # transient: back off and retry
            time.sleep(2)
            continue
        if r.status_code == 404:                      # empty window
            return None
        r.raise_for_status()
        return r.json()
    raise RuntimeError(f"gave up on {path}")

books = get("bookmakers")
print(f"{len(books)} bookmakers in the catalogue\n")

# 1xbet itself, 22bet, and every slug the catalogue flags as a 22bet clone
family = [b for b in books
          if b["slug"] in ("1xbet", "22bet") or b.get("cloneOf") == "22bet"]
for b in family:
    print(f'{b["slug"]:<10} {b["bookmakerName"]:<10} '
          f'liveOdds={b["liveOdds"]!s:<5} cloneOf={b["cloneOf"]}')
365 bookmakers in the catalogue

1xbet      1xBet      liveOdds=True  cloneOf=None
1xbit      1xBit      liveOdds=True  cloneOf=22bet
22bet      22Bet      liveOdds=True  cloneOf=None
betwinner  BetWinner  liveOdds=True  cloneOf=22bet
fairpari   FairPari   liveOdds=True  cloneOf=22bet
megapari   MegaPari   liveOdds=True  cloneOf=22bet
melbet     MelBet     liveOdds=True  cloneOf=22bet
spelet.lv  Spelet LV  liveOdds=True  cloneOf=22bet

The catalogue flags six slugs as clones of 22bet and leaves 1xbet unflagged. Nothing in /v4/bookmakers links 1xbet to the other seven. The event ID does that, in Step 2.

Step 2: group the eight slugs by event ID

This step takes the next NHL fixture, asks for the eight slugs, and groups them twice: first by bookmakerFixtureId and the host in fixturePath, then by the set of active prices each slug quotes.

# Reuses get() and the imports from Step 1.
import json
from collections import defaultdict

FAMILY = ["1xbet", "22bet", "1xbit", "betwinner", "fairpari",
          "megapari", "melbet", "spelet.lv"]
NHL = 234  # tournamentId, from /v4/fixtures

def active_prices(book):
    """Every active price a book quotes, keyed by (market, outcome, player)."""
    return {(mid, oid, pid): p["price"]
            for mid, m in book["markets"].items()
            for oid, o in m["outcomes"].items()
            for pid, p in (o.get("players") or {}).items()
            if p.get("active") and p.get("price")}

now = datetime.now(timezone.utc)
fixtures = get("fixtures", tournamentId=NHL,
               **{"from": now.strftime("%Y-%m-%d"),
                  "to": (now + timedelta(days=4)).strftime("%Y-%m-%d")})
fx = next(f for f in fixtures if f["hasOdds"] and f["startTime"] > now.isoformat())
print(fx["participant1Name"], "v", fx["participant2Name"], fx["startTime"])

odds = get("odds", fixtureId=fx["fixtureId"], bookmakers=",".join(FAMILY))
board = odds["bookmakerOdds"]

# 1. group the slugs by the bookmaker's own event ID and the host they link to
events = defaultdict(list)
for slug, book in board.items():
    host = book["fixturePath"].split("/")[2]
    events[book["bookmakerFixtureId"]].append(f"{slug} ({host})")
for event_id, slugs in events.items():
    print(f"\nevent ID {event_id}: {len(slugs)} slugs")
    for s in slugs:
        print("  ", s)

# 2. collapse slugs that quote byte-identical prices
books = defaultdict(list)
for slug, book in board.items():
    prices = active_prices(book)
    books[json.dumps(sorted(prices.items()))].append((slug, len(prices),
          sum(1 for m in book["markets"].values()
              if any(p.get("active") for o in m["outcomes"].values()
                     for p in (o.get("players") or {}).values()))))
print(f"\n{len(board)} slugs, {len(books)} distinct price books")
for members in books.values():
    slugs = [m[0] for m in members]
    print(f"  {len(slugs)} slug(s), {members[0][2]} active markets, "
          f"{members[0][1]} active prices: {', '.join(slugs)}")
Washington Capitals v Pittsburgh Penguins 2026-10-07T23:30:00.000Z

event ID 351619128: 8 slugs
   1xbet (1xbet.com)
   1xbit (22bet.com)
   22bet (22bet.com)
   betwinner (22bet.com)
   fairpari (22bet.com)
   megapari (22bet.com)
   melbet (22bet.com)
   spelet.lv (22bet.com)

8 slugs, 2 distinct price books
  1 slug(s), 54 active markets, 332 active prices: 1xbet
  7 slug(s), 118 active markets, 574 active prices: 1xbit, 22bet, betwinner, fairpari, megapari, melbet, spelet.lv

Eight slugs, one event ID, two price books. The seven 22bet.com slugs matched price for price on all 15 boards we compared on 7 October, across the NFL, MLB, NHL, EuroLeague, ATP Shanghai and the EFL Championship. Keep one of them in a consensus and drop the other six.

The 1xbet book is not a copy. On the NHL boards, most of its active prices matched 22bet, but the moneyline did not. Across the 7 October sample, the 22bet line carried 1.05 to 6.3 times as many active markets on 29 boards: 346 against 193 on West Ham v QPR, 363 against 271 on Cowboys v Buccaneers. Read the menu from 22bet and the headline price from 1xbet.

Step 3: compare the main-line margin across a slate

This step reads the main market (moneyline, winner or 1X2) for the next three fixtures in seven tournaments and prints the margin for 1xbet, 22bet and pinnacle. A market counts only when every leg is active.

# Reuses get() and the imports from Step 1.
# tournamentId -> the market that carries the headline price
SLATE = {31: "141",    # NFL, Winner (incl. overtime)
         234: "151",   # NHL, Winner (incl. overtime and penalties)
         109: "131",   # MLB, Winner (incl. extra innings)
         138: "111",   # EuroLeague, Winner (incl. overtime)
         3085: "121",  # ATP Shanghai singles, Winner
         325: "101",   # Brasileiro Serie A, Full Time Result
         18: "101"}    # EFL Championship, Full Time Result
BOOKS = ["1xbet", "22bet", "pinnacle"]

def overround(book, market_id):
    """Margin in % on one market, or None unless every leg is active."""
    m = book["markets"].get(market_id) if book else None
    if not m:
        return None
    legs = [o["players"]["0"] for o in m["outcomes"].values()]
    if not all(l.get("active") and l.get("price") for l in legs):
        return None
    return (sum(1 / l["price"] for l in legs) - 1) * 100

now = datetime.now(timezone.utc)
window = {"from": now.strftime("%Y-%m-%d"),
          "to": (now + timedelta(days=4)).strftime("%Y-%m-%d")}
rows = []
for tid, market_id in SLATE.items():
    fixtures = get("fixtures", tournamentId=tid, **window) or []
    upcoming = [f for f in fixtures
                if f["hasOdds"] and f["startTime"] > now.isoformat()][:3]
    for f in upcoming:
        odds = get("odds", fixtureId=f["fixtureId"], bookmakers=",".join(BOOKS))
        board = (odds or {}).get("bookmakerOdds", {})
        m = {s: overround(board.get(s), market_id) for s in BOOKS}
        if m["1xbet"] is None or m["22bet"] is None:
            continue
        rows.append(m)
        name = f'{f["participant1Name"]} v {f["participant2Name"]}'[:34]
        pin = f'{m["pinnacle"]:.2f}%' if m["pinnacle"] is not None else "-"
        print(f'{f["tournamentName"][:14]:<14} {name:<34} '
              f'1xbet {m["1xbet"]:.2f}%  22bet {m["22bet"]:.2f}%  pinnacle {pin}')
        time.sleep(1)

tighter = sum(1 for r in rows if r["1xbet"] < r["22bet"] - 0.005)
same = sum(1 for r in rows if abs(r["1xbet"] - r["22bet"]) <= 0.005)
print(f"\n{len(rows)} fixtures: 1xbet tighter on {tighter}, "
      f"identical on {same}, wider on {len(rows) - tighter - same}")
for s in BOOKS:
    vals = [r[s] for r in rows if r[s] is not None]
    print(f"median {s:<8} {median(vals):.2f}%  ({len(vals)} fixtures)")
NFL            Dallas Cowboys v Tampa Bay Buccane 1xbet 4.29%  22bet 5.42%  pinnacle 3.77%
NHL            Washington Capitals v Pittsburgh P 1xbet 3.09%  22bet 5.21%  pinnacle 2.46%
NHL            Winnipeg Jets v Colorado Avalanche 1xbet 3.12%  22bet 5.41%  pinnacle 2.66%
NHL            Anaheim Ducks v Edmonton Oilers    1xbet 3.12%  22bet 5.18%  pinnacle 2.61%
MLB            Chicago White Sox v Cleveland Guar 1xbet 2.03%  22bet 5.25%  pinnacle 2.01%
MLB            Atlanta Braves v Los Angeles Dodge 1xbet 2.03%  22bet 5.29%  pinnacle 1.95%
MLB            New York Yankees v Tampa Bay Rays  1xbet 2.06%  22bet 5.27%  pinnacle 2.02%
Euroleague     Paris Basketball v ASVEL Lyon-Vill 1xbet 3.63%  22bet 5.39%  pinnacle 3.78%
Euroleague     Maccabi Tel-Aviv v Olimpia Milano  1xbet 3.62%  22bet 5.15%  pinnacle 3.80%
Euroleague     Dubai Basketball v KK Crvena zvezd 1xbet 3.65%  22bet 5.30%  pinnacle 3.89%
ATP Shanghai,  Borges, Nuno v Diaz Acosta, Facund 1xbet 4.19%  22bet 5.43%  pinnacle 2.94%
ATP Shanghai,  Munar, Jaume v Brooksby, Jenson    1xbet 4.18%  22bet 5.29%  pinnacle 2.87%
ATP Shanghai,  Coppejans, Kimmer v Tsitsipas, Ste 1xbet 4.24%  22bet 5.51%  pinnacle 3.74%
Brasileiro Ser Red Bull Bragantino SP v Mirassol  1xbet 4.16%  22bet 5.45%  pinnacle 3.01%
Brasileiro Ser SC Internacional RS v SC Corinthia 1xbet 4.23%  22bet 5.40%  pinnacle 2.73%
Brasileiro Ser Clube do Remo PA v Gremio FB Porto 1xbet 4.21%  22bet 5.45%  pinnacle 2.80%
Championship   West Ham United v Queens Park Rang 1xbet 7.07%  22bet 7.07%  pinnacle 5.68%
Championship   Charlton Athletic v Bristol City   1xbet 7.01%  22bet 7.01%  pinnacle 5.03%
Championship   Swansea City v Norwich City        1xbet 7.44%  22bet 7.44%  pinnacle 4.85%

19 fixtures: 1xbet tighter on 16, identical on 3, wider on 0
median 1xbet    4.16%  (19 fixtures)
median 22bet    5.40%  (19 fixtures)
median pinnacle 2.94%  (19 fixtures)

We ran this on 7 October 2026 at 13:25 UTC. 1xbet priced the main line tighter than 22bet on 16 of 19 fixtures and matched it on the three Championship boards. The gap runs about 1.1 to 3.3 points. On MLB, 1xbet sat within 0.08 points of Pinnacle. On the EuroLeague, it priced the winner market tighter than Pinnacle on all three fixtures.

Check the price age before you trust a gap. On 18 of 29 pre-match boards we read that day, the 1xbet book carried bookmakerIsActive: false, and on 10 of those 18 its newest price had changed inside the last 30 minutes. For this book, read the price-level active flag and each price’s changedAt. Our line shopping guide shows how to pick the best price per leg once you have both books.

Step 4: check the closing line on played fixtures

A live margin tells you about one moment. The close tells you what the book settled on. This step pulls every played NFL Week 5 fixture from /v4/historical-odds and takes the last active price before kickoff on each side. Pass outcomeId to cut the payload: one Brasileiro fixture came back at 14.8 MB for three books, and 0.1 MB for one outcome.

# Reuses get() and the imports from Step 1.
BOOKS = "1xbet,22bet,pinnacle"
NFL, MONEYLINE = 31, ["141", "142"]   # Winner (incl. overtime), both legs

def closing_prices(fixture_id, kickoff, outcome_id):
    """Last active price before kickoff, per book, for one outcome."""
    hist = get("historical-odds", fixtureId=fixture_id,
               bookmakers=BOOKS, outcomeId=outcome_id)
    time.sleep(4.6)                    # /historical-odds needs a longer gap
    close = {}
    for slug, book in (hist or {}).get("bookmakers", {}).items():
        for market in book["markets"].values():
            for o in market["outcomes"].values():
                snaps = [s for s in o["players"].get("0", [])
                         if s["active"] and s["createdAt"] < kickoff]
                if snaps:
                    close[slug] = snaps[-1]["price"]
    return close

played = get("fixtures", tournamentId=NFL,
             **{"from": "2026-10-02", "to": "2026-10-07"})
played = [f for f in played if f["statusName"] == "Finished"]

margins = {s: [] for s in BOOKS.split(",")}
pairs = []
for f in played:
    kickoff = f["trueStartTime"] or f["startTime"]
    legs = [closing_prices(f["fixtureId"], kickoff, oid) for oid in MONEYLINE]
    row = {}
    for slug in margins:
        if all(slug in leg for leg in legs):
            row[slug] = (sum(1 / leg[slug] for leg in legs) - 1) * 100
            margins[slug].append(row[slug])
    if "1xbet" in row and "22bet" in row:
        pairs.append((row["1xbet"], row["22bet"]))
    print(f'{f["participant1Abbr"] or "":>4} v {f["participant2Abbr"] or "":<4}',
          "  ".join(f"{s} {v:.2f}%" for s, v in row.items()))

print(f"\n{len(played)} played NFL Week 5 fixtures, closing moneyline:")
for slug, vals in margins.items():
    print(f"  {slug:<8} median {median(vals):.2f}%  ({len(vals)} fixtures)")
print(f"  1xbet tighter than 22bet at the close on "
      f"{sum(1 for a, b in pairs if a < b - 0.005)} of {len(pairs)}, "
      f"identical on {sum(1 for a, b in pairs if abs(a - b) <= 0.005)}")
 CLE v PIT  1xbet 5.33%  22bet 5.33%  pinnacle 2.51%
 WAS v IND  1xbet 5.91%  22bet 5.39%  pinnacle 4.91%
 BAL v TEN  1xbet 5.26%  22bet 5.29%  pinnacle 3.21%
 BUF v NE   1xbet 5.19%  22bet 5.26%  pinnacle 3.00%
 CHI v NYJ  1xbet 5.21%  22bet 5.21%  pinnacle 2.71%
 CIN v JAX  1xbet 5.23%  22bet 5.23%  pinnacle 2.48%
 HOU v DAL  1xbet 5.23%  22bet 5.23%  pinnacle 2.58%
 NYG v ARI  1xbet 5.25%  22bet 5.25%  pinnacle 2.44%
 PHI v LA   1xbet 5.21%  22bet 5.21%  pinnacle 2.69%
  TB v GB   1xbet 5.23%  22bet 5.23%  pinnacle 2.44%
 MIN v MIA  1xbet 5.18%  22bet 5.22%  pinnacle 3.20%
  LV v KC   1xbet 4.34%  22bet 5.33%  pinnacle 2.72%
 SEA v LAC  1xbet 4.56%  22bet 5.34%  pinnacle 2.99%
  SF v DEN  1xbet 4.09%  22bet 5.20%  pinnacle 2.51%
 CAR v DET  1xbet 4.44%  22bet 5.26%  pinnacle 2.64%
  NO v ATL  1xbet 5.31%  22bet 5.31%  pinnacle 2.41%

16 played NFL Week 5 fixtures, closing moneyline:
  1xbet    median 5.22%  (16 fixtures)
  22bet    median 5.25%  (16 fixtures)
  pinnacle median 2.66%  (16 fixtures)
  1xbet tighter than 22bet at the close on 7 of 16, identical on 8

On the NFL, the gap mostly closes by kickoff. The two books closed identical on 8 of 16 moneylines, and 1xbet stayed tighter on 7. We ran the same check on 54 played fixtures across seven tournaments between 2 and 6 October:

Tournament (played, 2 to 6 Oct 2026) Fixtures 1xbet tighter at the close Identical Median close, 1xbet Median close, 22bet
NFL 12 5 6 5.21% 5.25%
MLB 8 6 2 2.05% 5.27%
NHL 10 5 5 4.71% 4.77%
ATP Shanghai singles 10 3 5 7.92% 8.04%
UEFA Nations League 9 4 1 4.25% 5.25%
WTA Beijing singles 3 2 0 4.85% 4.69%
Brasileiro Serie A 2 1 0 4.17% 4.14%
All 54 26 19

MLB is where the second book earns its slot. 1xbet closed six of eight postseason moneylines between 2.04% and 2.06%, while 22bet held 5.2% to 5.4%. On the Nations League, the two books split. So route per market and per tournament, and re-run the check on your own slate. The NFL sample in the table is the 12 fixtures from our bulk run; the snippet above reads all 16 Week 5 games.

Snapshots record polling, so collapse identical consecutive prices before you count line moves. For a full strategy test on these closes, start from our backtesting guide. For the speed question, our soft book lag study timed how fast 1xbet follows a Pinnacle move. To read the book live without a polling loop, use the WebSocket feed.

For a one-page view of the slug, see the 1xBet sportsbook page. For Stake and the other crypto and offshore sportsbooks, read the crypto bookmaker API guide.

1xBet API FAQ

How do I get 1xBet odds in Python?

Call /v4/odds with a fixtureId and bookmakers=1xbet, and pass your key as the apiKey query parameter. Add 22bet to the same call to get the second 1xBet price book, which carries the larger market menu.

Which bookmaker feeds share 1xBet’s event ID?

On 7 October 2026, eight slugs carried the same bookmakerFixtureId: 1xbet, plus 22bet, 1xbit, betwinner, fairpari, megapari, melbet and spelet.lv, which all link to 22bet.com.

Do 22Bet, MelBet and BetWinner quote the same odds as 1xBet?

22bet, 1xbit, betwinner, fairpari, megapari, melbet and spelet.lv quoted byte-identical prices on every board we checked. 1xbet runs its own price book on the same event, and priced the main line at a 4.16% median margin against 5.40% on 22bet across 19 live boards.

Does cloneOf tell me which books copy 1xBet?

It flags six slugs as clones of 22bet and leaves 1xbet unflagged. Group books on bookmakerFixtureId and on identical price sets to find the full family.

Can I get historical 1xBet odds?

Yes. /v4/historical-odds returns every 1xbet and 22bet snapshot on a played fixture, on the free tier. Across 54 played fixtures from 2 to 6 October 2026, 1xbet closed the main line tighter than 22bet on 26 and identical on 19.

Read both 1xBet price books from one key

Every call in this guide runs on the free key: 350+ bookmakers in the catalogue, free historical odds for the closing-line check, and a WebSocket feed when polling gets too slow. Get a free API key and run Step 3 on tonight’s slate.