Betano API: Access Betano Odds from Brazil, Europe & LATAM (Free)

Betano API - OddsPapi API Blog
How To Guides April 15, 2026

Does Betano have a public API? No. Betano does not offer a self-serve developer API, public odds feed, or affiliate endpoint you can hit with an API key. Their data is locked behind BetConstruct/Altenar-style enterprise contracts in a handful of regulated markets — Brazil (SPA), Germany (GlüStV), Denmark, Romania, and a growing list of LATAM countries. If you searched for “Betano API,” “Betano odds API,” or “Betano API documentation,” you already know it’s a dead end.

But the data itself is not locked. OddsPapi aggregates Betano odds across every regulated region Betano operates in, alongside 350+ other bookmakers including sharps like Pinnacle and Singbet, into a single REST API. Free tier. No enterprise contract. Here is exactly how to pull Betano odds in Python, how Betano’s regional pricing actually works under the hood, and how to find value against sharp books.

Why Betano Has No Public API

Betano is operated by Kaizen Gaming, headquartered in Greece. It is one of the largest sportsbooks in Brazil (estimated ~23% market share) and has expanded aggressively into Germany, Romania, Portugal, Czech Republic, Denmark, Bulgaria, Canada, Mexico, and Peru over the last few years. Every single one of those markets is regulated — and that is the entire problem if you want API access:

  • Licensing restrictions: Operating in Germany (GlüStV 2021), Brazil (SPA/Bets Law 14.790), Denmark (Spillemyndigheden), and Romania (ONJN) means Betano has to tightly control where its odds surface and to whom. Publishing a public API would require renegotiating multiple licenses at once.
  • Competitive moat: Kaizen’s trading desk prices dozens of tournaments in local-language markets that bigger books ignore — Brasileirão Série B, Superliga, 1. Bundesliga specials, Liga MX. Giving that pricing to competitors for free is not on the table.
  • B2B-only feeds: Any official Betano data access runs through BetConstruct or Altenar enterprise feeds — five-figure monthly contracts with strict redistribution terms. There is no self-serve tier.

This is the same story as Bet365, DraftKings, FanDuel, and Pinnacle. Big regulated books do not hand out odds data. Aggregators like OddsPapi collect this data through licensed channels and expose it through one clean REST API.

The 3 Ways to Get Betano Odds

Method Betano Coverage Cost Reliability Legal Risk
Scraping betano.com / betano.bet.br Partial (HTML parsing, one region at a time) Free (your time) Breaks on every UI update Violates ToS + regulated market risk
BetConstruct / Altenar enterprise feed Full €5,000–€15,000/month Stable None (contracted)
OddsPapi API Global + Brazil feeds, historical data, 350+ other bookmakers in same call Free tier available Licensed feeds, 99.9% uptime None

Scraping Betano is harder than it looks. Each regional domain (betano.de, betano.dk, betano.bet.br) runs a separate front end with its own anti-bot setup, its own region lock, and its own Cloudflare config. You end up maintaining nine scrapers instead of one. Enterprise feeds solve the reliability problem but start at mid-four-figures per month. OddsPapi sits in the middle: the same data, standardized across all 350+ books, on a free tier.

How Betano’s Regional Pricing Actually Works

This is the part most developers get wrong. Betano has nine regional domains, but they do not all price independently. Here is the actual breakdown from /v4/bookmakers, which exposes a cloneOf field that tells you which feeds are independently traded vs. mirrors of the global book:

Slug Region cloneOf What you actually get
betano Global (Kaizen core) Independent trading feed
betano.bet.br Brazil Independent Brazil-specific feed (diverges from global)
betano.de Germany betano Mirror of global feed
betano.dk Denmark betano Mirror of global feed
betano.bg Bulgaria betano Mirror of global feed
betano.ca Canada (Ontario) betano Mirror of global feed
betano.mx Mexico betano Mirror of global feed
betano.pe Peru betano Mirror of global feed
betano.co.uk UK betvictor ⚠ Not real Betano — this domain is a BetVictor skin

Three things to take away from this:

  1. Only two Betano feeds are independently priced: the global betano slug and the Brazil-specific betano.bet.br slug. The Brazil feed diverges from global because Brazilian trading is run locally by Kaizen’s São Paulo team and reflects different liquidity and demand.
  2. The European, Canadian, and LATAM regional slugs are clones. Pulling betano.de returns the same prices as betano. They exist as separate slugs so regulators can track them per-jurisdiction, but there is no extra data to be mined by hitting all of them in parallel.
  3. betano.co.uk is not Betano. The UK domain is licensed as a BetVictor skin (Betano does not hold a UKGC license). OddsPapi flags this explicitly in cloneOf: "betvictor" — do not use this slug if you are expecting real Betano prices.

In practice, if you want full Betano coverage, you only need to query two slugs: betano and betano.bet.br. Anything else is a mirror or a different book.

Python Tutorial: Pull Betano Odds via OddsPapi

Here is the full end-to-end workflow. You will go from zero to pulling live Betano soccer odds in about three minutes. Every snippet below has been tested against the live OddsPapi API.

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}

# Sanity check
r = requests.get(f"{BASE_URL}/sports", params=params)
print(r.status_code)  # 200

Important: The API key goes in ?apiKey=KEY, not in an Authorization header. This catches most developers on their first call.

Step 2: Enumerate Betano Regional Slugs

# Pull the full bookmaker catalog and filter to Betano variants
r = requests.get(f"{BASE_URL}/bookmakers", params={"apiKey": API_KEY})
books = r.json()

betano_feeds = [b for b in books if "betano" in b["slug"]]
for b in betano_feeds:
    clone = b.get("cloneOf") or "INDEPENDENT"
    print(f"{b['slug']:18} live={b['liveOdds']!s:5} cloneOf={clone}")

# Output:
# betano             live=True  cloneOf=INDEPENDENT
# betano.bet.br      live=True  cloneOf=INDEPENDENT
# betano.bg          live=True  cloneOf=betano
# betano.ca          live=True  cloneOf=betano
# betano.co.uk       live=False cloneOf=betvictor   <-- not Betano
# betano.de          live=True  cloneOf=betano
# betano.dk          live=True  cloneOf=betano
# betano.mx          live=True  cloneOf=betano
# betano.pe          live=True  cloneOf=betano

Use the cloneOf field to filter down to what you actually need. If cloneOf is None, the slug is an independently traded feed. Otherwise it is either a mirror or a different book entirely.

# Keep only the independently traded Betano feeds
real_betano = [b["slug"] for b in betano_feeds
               if b.get("cloneOf") is None and b["liveOdds"]]
print(real_betano)
# ['betano', 'betano.bet.br']

Step 3: 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")
}

r = requests.get(f"{BASE_URL}/fixtures", params=params)
with_odds = [f for f in r.json() if f.get("hasOdds")]
print(f"{len(with_odds)} fixtures with odds in the next 3 days")

for fix in with_odds[:5]:
    print(f"  {fix['fixtureId']} | tournament {fix['tournamentId']} | {fix['startTime']}")

OddsPapi terminology: a "game" is a fixture, a "league" is a tournament, a "team" is a participant. Only fixtures with hasOdds: true return odds from /v4/odds.

Step 4: Pull Betano Odds for a Fixture

fixture_id = with_odds[0]["fixtureId"]

# Query both independent Betano feeds plus Pinnacle for comparison
r = requests.get(f"{BASE_URL}/odds", params={
    "apiKey": API_KEY,
    "fixtureId": fixture_id,
    "bookmakers": "betano,betano.bet.br,pinnacle"
})
data = r.json()
bk = data.get("bookmakerOdds", {})
print(f"Books returned: {list(bk.keys())}")

Step 5: Parse the Nested JSON

OddsPapi's odds response is nested — never assume flat JSON. Here is the exact path to a price:

# Path:
# bookmakerOdds -> [slug] -> markets -> [marketId] -> outcomes -> [outcomeId] -> players -> "0" -> price

# Market 101 = Full Time Result (1X2)
# Outcomes: 101 = Home, 102 = Draw, 103 = Away

def extract_1x2(bk, slug):
    try:
        o = bk[slug]["markets"]["101"]["outcomes"]
        return {
            "home": o["101"]["players"]["0"]["price"],
            "draw": o["102"]["players"]["0"]["price"],
            "away": o["103"]["players"]["0"]["price"]
        }
    except KeyError:
        return None

for slug in ["betano", "betano.bet.br", "pinnacle"]:
    prices = extract_1x2(bk, slug)
    if prices:
        print(f"{slug:15} H={prices['home']} D={prices['draw']} A={prices['away']}")

# Real output from a live Brasileirão fixture (Apr 2026):
# betano          H=2.72 D=3.25 A=2.52
# betano.bet.br   H=2.55 D=3.25 A=2.72
# pinnacle        H=2.55 D=3.35 A=2.79

Notice the gap between betano (global) and betano.bet.br (Brazil) on the same fixture. Brazilian bettors were getting 2.72 on the Home team while global users saw 2.52. That is Kaizen's Brazil trading team pricing local demand differently from their European book — and you cannot see that divergence unless you pull both slugs explicitly.

Step 6: Line Shop Betano vs. Pinnacle

Betano is a "soft" bookmaker — they build in recreational-friendly margins and limit winning accounts. Pinnacle is the sharp benchmark. Here is a simple line-shopping script that flags every fixture where Betano diverges from Pinnacle by more than 3%:

def find_betano_edges(fixture_ids, threshold=0.03):
    edges = []
    for fid in fixture_ids:
        r = requests.get(f"{BASE_URL}/odds", params={
            "apiKey": API_KEY,
            "fixtureId": fid,
            "bookmakers": "betano,betano.bet.br,pinnacle"
        })
        bk = r.json().get("bookmakerOdds", {})
        if "pinnacle" not in bk:
            continue

        for betano_slug in ("betano", "betano.bet.br"):
            if betano_slug not in bk:
                continue
            b_markets = bk[betano_slug]["markets"]
            p_markets = bk["pinnacle"]["markets"]

            for mid in b_markets.keys() & p_markets.keys():
                b_out = b_markets[mid]["outcomes"]
                p_out = p_markets[mid]["outcomes"]
                for oid in b_out.keys() & p_out.keys():
                    try:
                        b_price = b_out[oid]["players"]["0"]["price"]
                        p_price = p_out[oid]["players"]["0"]["price"]
                    except (KeyError, TypeError):
                        continue
                    if b_price <= 1 or p_price <= 1:
                        continue
                    edge = (b_price - p_price) / p_price
                    if abs(edge) > threshold:
                        edges.append({
                            "fixture": fid,
                            "book": betano_slug,
                            "market": mid,
                            "outcome": oid,
                            "betano": b_price,
                            "pinnacle": p_price,
                            "edge_pct": round(edge * 100, 2)
                        })
    return sorted(edges, key=lambda x: abs(x["edge_pct"]), reverse=True)

edges = find_betano_edges([f["fixtureId"] for f in with_odds[:20]])
for e in edges[:10]:
    print(e)

Every result here is a spot where Betano's price is either above or below the Pinnacle benchmark. Positive edges (Betano offering more than Pinnacle) are where value bettors hunt for +EV plays. Negative edges are where Betano has shaded the line to manage recreational action. Either way, you need both feeds to see it — which is exactly what a one-API-call aggregator gives you.

Step 7: Market & Outcome Name Lookup

Market IDs like 101 and 1010 are integers. To turn them into human-readable names, query /v4/markets?sportId=10 and build a lookup dict:

r = requests.get(f"{BASE_URL}/markets",
                 params={"apiKey": API_KEY, "sportId": 10})
catalog = r.json()

market_names = {m["marketId"]: m["marketName"] for m in catalog}
outcome_names = {
    (m["marketId"], o["outcomeId"]): o["outcomeName"]
    for m in catalog for o in m.get("outcomes", [])
}

print(market_names[101])           # 'Full Time Result'
print(outcome_names[(101, 101)])   # 'Home'

Soccer alone has over 32,000 market IDs when you count every handicap/total line variant, so never hardcode the full catalog — always build the lookup from /v4/markets at runtime.

Betano vs. Pinnacle: Why You Need Both

Factor Betano (Soft) Pinnacle (Sharp)
Target market Recreational bettors in Brazil + Europe + LATAM Professional bettors globally
Margin (overround) 5–8% on 1X2, higher on props 2–3%
Line accuracy Follows the sharp market Sets the market
Account limits Limits winning accounts aggressively No limits, ever
Local specials Deep Brasileirão, Bundesliga, Liga MX coverage Global top-tier only
Best use Finding +EV mispricing in Brazilian + LATAM leagues True odds reference

Pinnacle closing lines are as close to "true probability" as you get in sports betting. When Betano diverges from Pinnacle, that is either a mispriced market or a shaded line managing recreational action. In either case, you need both data sets to find the edge — and Betano specifically is the book to cross-check against for Brazilian and LATAM fixtures where Pinnacle's local coverage is thinner.

For a deeper look at how Brazilian books price their home leagues differently, read our companion post on the Brazilian betting API ecosystem — it covers Betano alongside EstrelaBet, Stake BR, Superbet BR, and Pixbet.

Free Betano Historical Odds

Most odds APIs charge extra for historical data — The Odds API locks it behind their Mega plan, SportsGameOdds charges $299+/month. OddsPapi includes Betano historical odds on the free tier. Here is how to pull the full price history for any past fixture:

# Historical odds endpoint — max 3 bookmakers per call
r = requests.get(f"{BASE_URL}/historical-odds", params={
    "apiKey": API_KEY,
    "fixtureId": fixture_id,
    "bookmakers": "betano,betano.bet.br,pinnacle"
})
data = r.json()

# NOTE: historical endpoint uses 'bookmakers' (NOT 'bookmakerOdds')
# and players["0"] is a LIST of snapshots, not a dict
for slug, book in data["bookmakers"].items():
    snaps = book["markets"]["101"]["outcomes"]["101"]["players"]["0"]
    print(f"\n{slug}: {len(snaps)} price snapshots for Home")
    for s in snaps[-3:]:  # last 3 moves
        print(f"  {s['createdAt']}  price={s['price']}")

That is the full price history for the Home outcome, timestamped to the second. Use it to build closing-line-value models, track how Betano Brazil moves vs. global Betano, or backtest strategies against real Betano historical data — all on the free tier.

Two gotchas on the historical endpoint: the top-level key is bookmakers (not bookmakerOdds), and players["0"] is a list of snapshots rather than a single dict. Do not copy-paste your live-odds parser and expect it to work.

Frequently Asked Questions

Does Betano have a public API?

No. Betano is operated by Kaizen Gaming and does not publish a public API, developer documentation, or self-serve API keys. Data access is restricted to BetConstruct/Altenar enterprise contracts in the regulated markets where Betano operates. OddsPapi aggregates Betano odds through licensed feeds and exposes them via a standard REST API with a free tier.

Is scraping betano.com legal?

Scraping violates Betano's terms of service and runs into additional regulatory risk in licensed markets like Germany (GlüStV) and Brazil (SPA). It is also technically brittle — each regional domain runs its own anti-bot stack. Using a licensed aggregator like OddsPapi avoids both problems.

Which Betano regions does OddsPapi actually cover?

Nine Betano slugs exist in the OddsPapi bookmaker catalog, but only two are independently priced: betano (the global Kaizen trading feed) and betano.bet.br (the Brazil-specific feed). The other regional slugs (.de, .dk, .mx, .bg, .ca, .pe) are clones of the global feed, surfaced separately for jurisdiction tracking. Use the cloneOf field in /v4/bookmakers to disambiguate — hitting all nine in parallel returns the same data as hitting betano once.

Why does betano.bet.br have different prices than the global betano feed?

Kaizen Gaming runs a separate São Paulo trading desk for its Brazil license. That desk prices Brasileirão, Copa do Brasil, and other local competitions to reflect Brazilian demand and liquidity, which often diverges from the global book. In live testing, we have seen 1X2 gaps of up to 8% between the two feeds on Brasileirão fixtures.

Is betano.co.uk a real Betano feed?

No. Betano does not hold a UK Gambling Commission license. The betano.co.uk slug in OddsPapi is flagged as cloneOf: "betvictor" — it is a BetVictor skin, not real Betano. Do not use this slug if you need actual Betano prices.

Is the Betano data real-time?

Yes. REST responses reflect the latest available Betano odds, typically with sub-second refresh behind the scenes. For streaming updates, OddsPapi offers WebSocket connections on paid plans that push Betano line movements as they happen — no polling required.

How much does it cost to access Betano odds through OddsPapi?

OddsPapi offers a free tier with enough requests to build and test. Paid plans start at $29/month for higher rate limits and WebSocket access. Compare that to enterprise BetConstruct or Altenar feeds, which start in the low-four-figures per month and require a B2B contract.

Can I get Betano player props and in-play markets?

Player props and in-play markets are available where Betano publishes them. Soccer coverage includes 1X2, both teams to score, over/under totals, Asian handicaps, correct score, and period markets. Query /v4/markets?sportId=10 for the full live catalog — the market list is too large and too dynamic to hardcode.

Stop Searching for a Betano API That Does Not Exist

Betano will never publish a public API. They are a regulated sportsbook operating under licenses in ten-plus jurisdictions and every one of those licenses would need to be renegotiated to allow it. But if what you actually need is Betano odds — real-time prices across global and Brazil feeds, historical line movements, deep Brasileirão coverage — OddsPapi already has the data.

350+ bookmakers. Sharps like Pinnacle and Singbet for benchmarking. Brazil's full local book lineup. Free historical data. All through one REST API with a free tier.

Grab your free OddsPapi key — Betano odds in your first API call.