Bet365 API: How to Access Bet365 Odds Without Official API
Does Bet365 have a public API? No. Bet365 does not offer a public odds API, developer documentation, or self-serve API keys. Their data is locked behind enterprise contracts, affiliate partnerships, and internal systems. If you have searched for “Bet365 API,” “Bet365 odds API,” or “Bet365 API documentation,” you already know this. The official path is a dead end.
But the data itself is not locked — you just need a different way to get it. OddsPapi aggregates Bet365 odds alongside 350+ other bookmakers (including sharps like Pinnacle and Singbet) into a single REST API. Free tier. No enterprise contract. No scraping. Here is how to get Bet365 data in under 5 minutes.
Why Bet365 Has No Public API
Bet365 is the world’s largest online bookmaker. They process more bets per day than most competitors process in a week. Their odds data is proprietary, and they have zero incentive to hand it to developers for free. Here is why:
- Competitive moat: Bet365 prices lines across 50+ sports with one of the deepest market offerings in the industry. Giving that data away lets competitors react to their moves in real time.
- Regulatory constraints: Operating across 100+ countries means Bet365 tightly controls where their data surfaces and who accesses it.
- Enterprise-only feeds: If Bet365 shares data, it is through private enterprise or affiliate partnerships with strict licensing terms — not a self-serve API key you can grab in 5 minutes.
This is the same playbook as DraftKings, FanDuel, and Pinnacle. The biggest sportsbooks do not offer public APIs. But aggregators like OddsPapi collect this data through licensed feeds and expose it through a single, standardized endpoint.
Scraping vs. Enterprise vs. OddsPapi
| Method | Bet365 Data | Cost | Reliability | Legal Risk |
|---|---|---|---|---|
| Scraping bet365.com | Partial (HTML parsing) | Free (your time) | Breaks constantly | Violates ToS |
| Enterprise / Affiliate Feed | Full | $10,000+/month | Stable | None (contracted) |
| OddsPapi API | Full — 4 major sports, 2,000+ tournaments | Free tier available | 99.9% uptime, licensed feeds | None |
Scraping Bet365 is a losing battle. They run some of the most aggressive anti-bot measures in the industry — IP blocking, fingerprinting, CAPTCHAs. Your scraper will break within days. Enterprise feeds cost five figures per month and require a business relationship most developers will never have. OddsPapi gives you the same Bet365 data through a clean REST API with a free tier.
What Bet365 Data Is Available Through OddsPapi
OddsPapi pulls Bet365 odds across every major sport. Here is the verified coverage as of April 2026:
| Sport | Bet365 Markets | Tournaments | Total Bookmakers |
|---|---|---|---|
| Soccer | 8+ (1X2, BTTS, over/under, correct score) | 1,380 | 99+ |
| Basketball | 4+ (moneylines, spreads, totals) | 466 | 52+ |
| Baseball | Run lines, totals, moneylines | 66 | 109+ |
| Ice Hockey | 6+ (puck lines, totals, moneylines) | 119 | 72+ |
That is not just match winners. OddsPapi captures Bet365 pre-match markets including correct score, both teams to score, over/under lines, and more. All pulled from licensed data feeds and updated continuously.
And here is the part most people miss: when you pull Bet365 odds through OddsPapi, you also get odds from 350+ other bookmakers in the same API call. That means you can compare Bet365 lines against Pinnacle (the sharp benchmark), Singbet (Asian sharp), 1xBet (crypto), and 90+ other books — all in one response.
Python Tutorial: Get Bet365 Odds via OddsPapi
Here is the complete workflow. You will go from zero to pulling Bet365 soccer odds in about 3 minutes.
Step 1: Authenticate
import requests
from datetime import datetime, timedelta, timezone
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.oddspapi.io/v4"
# All requests use the apiKey query parameter (not headers)
params = {"apiKey": API_KEY}
# Test your connection
response = requests.get(f"{BASE_URL}/sports", params=params)
print(response.json())
# Returns: [{"sportId": 10, "slug": "soccer", "sportName": "Soccer"}, ...]
Important: The API key goes in the query parameter (?apiKey=KEY), not in headers. This catches most people on their first call.
Step 2: Find Soccer Fixtures
# Soccer = sportId 10
# Fixtures require a date range (max 10 days apart)
now = datetime.now(timezone.utc)
params = {
"apiKey": API_KEY,
"sportId": 10,
"from": now.strftime("%Y-%m-%dT%H:%M:%SZ"),
"to": (now + timedelta(days=3)).strftime("%Y-%m-%dT%H:%M:%SZ")
}
response = requests.get(f"{BASE_URL}/fixtures", params=params)
fixtures = response.json()
# Filter to fixtures that have odds
with_odds = [f for f in fixtures if f.get("hasOdds")]
print(f"Found {len(with_odds)} fixtures with odds")
for fix in with_odds[:5]:
print(f" {fix['fixtureId']} | Tournament {fix['tournamentId']} | {fix['startTime']}")
OddsPapi terminology: What you call a “game” is a fixture. What you call a “league” is a tournament. What you call a “team” is a participant.
Step 3: Pull Bet365 Odds
# Pick a fixture
fixture_id = with_odds[0]["fixtureId"]
# Get odds from all bookmakers
response = requests.get(f"{BASE_URL}/odds", params={
"apiKey": API_KEY,
"fixtureId": fixture_id
})
odds_data = response.json()
# Extract Bet365 odds
bookmaker_odds = odds_data["bookmakerOdds"]
if "bet365" in bookmaker_odds:
b365 = bookmaker_odds["bet365"]
b365_markets = b365["markets"]
print(f"Bet365 markets available: {len(b365_markets)}")
print(f"Market IDs: {list(b365_markets.keys())}")
# Market 101 = Full Time Result (1X2)
if "101" in b365_markets:
outcomes = b365_markets["101"]["outcomes"]
home = outcomes["101"]["players"]["0"]["price"]
draw = outcomes["102"]["players"]["0"]["price"]
away = outcomes["103"]["players"]["0"]["price"]
print(f"Bet365 1X2: Home {home} | Draw {draw} | Away {away}")
The odds JSON is nested. The path to any price is: bookmakerOdds → [slug] → markets → [marketId] → outcomes → [outcomeId] → players → "0" → price. Once you understand this structure, every bookmaker and every market follows the same pattern.
Step 4: Compare Bet365 vs. Sharp Lines
# Compare Bet365 (soft) vs Pinnacle (sharp) on the same fixture
def compare_1x2(odds_data, market_id="101"):
bk = odds_data["bookmakerOdds"]
books = {"bet365": "Bet365", "pinnacle": "Pinnacle", "singbet": "Singbet"}
results = {}
for slug, name in books.items():
if slug in bk and market_id in bk[slug]["markets"]:
outcomes = bk[slug]["markets"][market_id]["outcomes"]
results[name] = {
"home": outcomes["101"]["players"]["0"]["price"],
"draw": outcomes["102"]["players"]["0"]["price"],
"away": outcomes["103"]["players"]["0"]["price"]
}
return results
comparison = compare_1x2(odds_data)
for book, prices in comparison.items():
print(f"{book}: Home {prices['home']} | Draw {prices['draw']} | Away {prices['away']}")
# Example output:
# Bet365: Home 3.40 | Draw 3.90 | Away 1.83
# Pinnacle: Home 3.47 | Draw 4.02 | Away 1.94
# Singbet: Home 3.10 | Draw 3.80 | Away 1.87
Notice Pinnacle offers 4.02 on the draw while Bet365 offers 3.90. That gap is the soft book margin — and it is where value bettors and arbitrageurs make their money. Having both in one API call is the entire point.
Bet365 vs. Pinnacle: Why You Need Both
Bet365 is a “soft” bookmaker — they build in higher margins and limit winning accounts. Pinnacle is a “sharp” bookmaker — they welcome professional bettors and operate on razor-thin margins. Here is why that matters for your models:
| Factor | Bet365 (Soft) | Pinnacle (Sharp) |
|---|---|---|
| Target Market | Recreational bettors | Professional bettors |
| Margin (Overround) | 5-8% | 2-3% |
| Line Accuracy | Follows market | Sets the market |
| Account Limits | Limits winning bettors aggressively | No limits, ever |
| Closing Line Value | Often mispriced vs closing | The benchmark for CLV |
| Best Use | Finding +EV mispricing | True odds reference |
Pinnacle closing lines are the closest thing to “true probability” in sports betting. When Bet365 diverges from Pinnacle, that is a signal. Either Bet365 has mispriced the market, or they are shading lines to manage recreational action. Either way, you need both data sets to find the edge.
OddsPapi gives you both — plus Singbet, SBOBet, Betfair Exchange, and 350+ other books — in the same API call.
Build a Bet365 Line Shopping Tool
Here is a practical script that compares Bet365 lines against the sharpest bookmakers on every available fixture:
import requests
from datetime import datetime, timedelta, timezone
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.oddspapi.io/v4"
def get_fixtures(sport_id=10):
"""Get upcoming fixtures with odds."""
now = datetime.now(timezone.utc)
resp = requests.get(f"{BASE_URL}/fixtures", params={
"apiKey": API_KEY,
"sportId": sport_id,
"from": now.strftime("%Y-%m-%dT%H:%M:%SZ"),
"to": (now + timedelta(days=2)).strftime("%Y-%m-%dT%H:%M:%SZ")
})
return [f for f in resp.json() if f.get("hasOdds")]
def find_bet365_value(fixture_id, threshold=0.03):
"""Compare Bet365 vs Pinnacle, flag gaps above threshold."""
resp = requests.get(f"{BASE_URL}/odds", params={
"apiKey": API_KEY,
"fixtureId": fixture_id
})
bk = resp.json().get("bookmakerOdds", {})
if "bet365" not in bk or "pinnacle" not in bk:
return []
b365_markets = bk["bet365"]["markets"]
pin_markets = bk["pinnacle"]["markets"]
gaps = []
for market_id in b365_markets:
if market_id not in pin_markets:
continue
b365_outcomes = b365_markets[market_id]["outcomes"]
pin_outcomes = pin_markets[market_id]["outcomes"]
for outcome_id in b365_outcomes:
if outcome_id not in pin_outcomes:
continue
try:
b365_price = b365_outcomes[outcome_id]["players"]["0"]["price"]
pin_price = pin_outcomes[outcome_id]["players"]["0"]["price"]
except (KeyError, TypeError):
continue
if b365_price > 1 and pin_price > 1:
edge = (b365_price - pin_price) / pin_price
if abs(edge) > threshold:
gaps.append({
"market": market_id,
"outcome": outcome_id,
"bet365": b365_price,
"pinnacle": pin_price,
"edge_pct": round(edge * 100, 2)
})
return sorted(gaps, key=lambda x: abs(x["edge_pct"]), reverse=True)
# Scan upcoming soccer fixtures
fixtures = get_fixtures(sport_id=10)
print(f"Scanning {len(fixtures)} soccer fixtures for Bet365 vs Pinnacle gaps...\n")
for fix in fixtures[:20]:
gaps = find_bet365_value(fix["fixtureId"])
if gaps:
print(f"Fixture {fix['fixtureId']} (Tournament {fix['tournamentId']})")
for g in gaps[:3]:
sign = "+" if g["edge_pct"] > 0 else ""
print(f" Market {g['market']}: B365 {g['bet365']} vs PIN {g['pinnacle']} ({sign}{g['edge_pct']}%)")
print()
This script flags every fixture where Bet365 prices diverge from Pinnacle — the kind of edge that line shoppers and arb scanners depend on. Without access to both books in one API call, building this would require two separate scrapers, two different data formats, and constant maintenance.
Bet365 Historical Odds: Free on OddsPapi
Most APIs charge for historical data. The Odds API locks it behind their Mega plan. SportsGameOdds charges $299+/month. OddsPapi includes Bet365 historical odds on the free tier.
This is critical for backtesting. If you are building a model that predicts outcomes, you need historical closing lines to validate it. With OddsPapi, you can pull Bet365 closing odds for any past fixture and compare them against Pinnacle closing lines — the gold standard for measuring model accuracy.
For a deep dive into backtesting with Bet365 historical data, read our full guide: Bet365 Historical Odds Guide: The Data, APIs, and Strategy.
Frequently Asked Questions
Does Bet365 have a public API?
No. Bet365 does not offer a public API, developer portal, or self-serve API keys. Their odds data is only accessible through enterprise partnerships with strict licensing terms. OddsPapi aggregates Bet365 odds through licensed data feeds, making them accessible via a standard REST API with a free tier.
Can I scrape Bet365 for odds data?
Technically possible, but Bet365 runs some of the most aggressive anti-bot detection in the industry. Expect IP bans, CAPTCHAs, and constant breakage. It also violates their Terms of Service. Using an aggregator API like OddsPapi is more reliable, legal, and takes 5 minutes instead of 5 weeks.
How many Bet365 markets does OddsPapi cover?
OddsPapi covers 8+ Bet365 markets per soccer fixture (1X2, BTTS, over/under, correct score, and more), with similar depth for basketball, baseball, and ice hockey. Market availability varies by sport and tournament.
How much does it cost to access Bet365 odds through OddsPapi?
OddsPapi offers a free tier with 250 requests per month — enough to build and test. Paid plans start at $29/month for higher rate limits and WebSocket access. Compare that to enterprise Bet365 feeds at $10,000+/month.
Can I get historical Bet365 odds for free?
Yes. OddsPapi includes Bet365 historical odds on the free tier. Backtest models, track line movements, and compare closing lines — all without paying extra. Most competitors charge $299+/month for the same data.
Is the Bet365 data real-time?
Yes. REST API responses reflect the latest available Bet365 odds. For streaming updates, OddsPapi also offers WebSocket connections on paid plans that push Bet365 line movements as they happen.
Stop Searching for a Bet365 API That Does Not Exist
Bet365 will never give you a public API key. They are the biggest sportsbook on the planet and they did not get there by handing out their data. But if what you actually need is Bet365 odds — real-time prices, historical lines, market depth — OddsPapi already has it.
350+ bookmakers. Sharps like Pinnacle and Singbet. The world’s biggest soft book in Bet365. Crypto books like 1xBet. All through one REST API with a free tier and historical data included.
Get your free API key at oddspapi.io — Bet365 odds in your first API call.