The Brazil Betting Boom: The Best Odds API for EstrelaBet, Betano & Brasileirão

How To Guides January 17, 2026

The Brazil Betting Boom is Here—But Where’s the API?

Brazil just became the world’s hottest regulated sports betting market. On January 1, 2025, federal regulation kicked in, turning a gray market into a $10+ billion opportunity. Analysts project Brazil will hit $10B in Gross Gaming Revenue by 2029—putting it on track to rival the US market.

The local players are massive: Betano holds roughly 23% market share. EstrelaBet, Blaze, Stake BR, and Pixbet are all fighting for the rest. These aren’t small-time operators—they’re billion-dollar businesses with odds data that arbitrageurs and quants desperately want.

The problem? None of them offer a public API.

If you’re a developer trying to pull odds from EstrelaBet or Betano, your options are grim: scrape their sites (and risk getting banned), pay enterprise rates ($500+/month) for partial coverage, or give up entirely.

There’s a third option. OddsPapi aggregates odds from 300+ bookmakers—including all major Brazilian operators—into a single API. Free tier included. Historical data for backtesting. No scraping required.

Old Way vs. OddsPapi

Old Way OddsPapi
Scrape EstrelaBet (risk ban, legal gray area) One API call with estrelabet slug
No Betano API exists publicly betano.bet.br available in responses
Pay $500+/month for enterprise data Free tier + historical data for backtesting
Most APIs cover ~40 bookmakers max 300+ bookmakers including all Brazilian locals
No sharp book benchmarks Pinnacle, Singbet included for value detection

Brazilian Bookmakers Available via OddsPapi

These are the Brazilian-licensed operators you can access with a single API call:

Bookmaker API Slug Coverage
EstrelaBet estrelabet Full odds
Stake BR stake.bet.br Full odds
Sportingbet BR sportingbet.bet.br Full odds
Superbet BR superbet.bet.br Full odds
Blaze blaze.bet.br Full odds
KTO kto Full odds
Pixbet pixbet Full odds
Brazino777 brazino777.bet.br Full odds

Tutorial: Build a Brazilian Bookmaker Arbitrage Scanner

Let’s build a Python script that compares odds across EstrelaBet, Stake BR, and Sportingbet to identify arbitrage opportunities on Brazilian football fixtures.

Step 1: Authentication

OddsPapi uses query parameter authentication—not headers. This is important.

import requests

API_KEY = "YOUR_API_KEY"  # Get free key at oddspapi.io
BASE_URL = "https://api.oddspapi.io/v4"

# Always pass apiKey as query parameter
params = {"apiKey": API_KEY}
response = requests.get(f"{BASE_URL}/sports", params=params)
print(response.status_code)  # Should be 200

Step 2: Get Brazilian Football Fixtures

First, pull upcoming soccer fixtures and filter for Brazil. Note: date range must be under 10 days.

from datetime import datetime, timedelta

# Date range (max 10 days apart)
today = datetime.now().strftime('%Y-%m-%d')
next_week = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%d')

# Fetch soccer fixtures (sportId=10)
response = requests.get(f"{BASE_URL}/fixtures", params={
    "apiKey": API_KEY,
    "sportId": 10,
    "from": today,
    "to": next_week
})

fixtures = response.json()

# Filter for Brazilian fixtures with odds
brazil_fixtures = [
    f for f in fixtures
    if "brazil" in f.get("categorySlug", "").lower()
    and f.get("hasOdds", False)
]

print(f"Found {len(brazil_fixtures)} Brazilian fixtures with odds")

# Sample output
for f in brazil_fixtures[:5]:
    print(f"{f['participant1Name']} vs {f['participant2Name']}")

Step 3: Fetch Odds from Multiple Brazilian Bookmakers

The odds response is nested JSON. Here’s how to parse it correctly:

# Get odds for a specific fixture
fixture_id = brazil_fixtures[0]["fixtureId"]

response = requests.get(f"{BASE_URL}/odds", params={
    "apiKey": API_KEY,
    "fixtureId": fixture_id
})

data = response.json()
bookmaker_odds = data.get("bookmakerOdds", {})

# Target Brazilian bookmakers
target_slugs = ["estrelabet", "stake.bet.br", "sportingbet.bet.br", "superbet.bet.br"]

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

for slug in target_slugs:
    if slug not in bookmaker_odds:
        continue

    markets = bookmaker_odds[slug].get("markets", {})

    if "101" not in markets:
        continue

    outcomes = markets["101"]["outcomes"]

    # Extract prices (nested path: outcomes -> outcomeId -> players -> "0" -> price)
    home = outcomes.get("101", {}).get("players", {}).get("0", {}).get("price", "-")
    draw = outcomes.get("102", {}).get("players", {}).get("0", {}).get("price", "-")
    away = outcomes.get("103", {}).get("players", {}).get("0", {}).get("price", "-")

    print(f"{slug}: Home {home} | Draw {draw} | Away {away}")

Step 4: Arbitrage Detection Logic

An arbitrage exists when the sum of implied probabilities across the best odds is less than 100%.

def calculate_arb(home_odds, draw_odds, away_odds):
    """
    Calculate if there's an arbitrage opportunity.

    Returns:
        tuple: (total_implied_probability, profit_percentage)
        - If total_implied < 1.0, there's an arb opportunity
        - profit_percentage shows potential gain
    """
    implied_home = 1 / home_odds
    implied_draw = 1 / draw_odds
    implied_away = 1 / away_odds

    total_implied = implied_home + implied_draw + implied_away

    if total_implied < 1.0:
        profit = (1 - total_implied) * 100
        return total_implied, profit

    return total_implied, 0

# Example
total, profit = calculate_arb(2.90, 3.15, 2.85)
print(f"Total implied: {total:.4f}")
print(f"Profit margin: {profit:.2f}%")

Step 5: Complete Brazilian Arb Scanner

Here's the full working script that scans Brazilian fixtures for arbitrage opportunities:

import requests
from datetime import datetime, timedelta

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.oddspapi.io/v4"

def get_brazil_fixtures():
    """Fetch upcoming Brazilian football fixtures."""
    today = datetime.now().strftime('%Y-%m-%d')
    next_week = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%d')

    response = requests.get(f"{BASE_URL}/fixtures", params={
        "apiKey": API_KEY,
        "sportId": 10,
        "from": today,
        "to": next_week
    })

    fixtures = response.json()
    return [f for f in fixtures
            if "brazil" in f.get("categorySlug", "").lower()
            and f.get("hasOdds", False)]

def get_best_odds(fixture_id, target_bookies):
    """Get best odds across specified bookmakers for 1X2 market."""
    response = requests.get(f"{BASE_URL}/odds", params={
        "apiKey": API_KEY,
        "fixtureId": fixture_id
    })

    if response.status_code != 200:
        return None

    bookmaker_odds = response.json().get("bookmakerOdds", {})

    best = {
        "home": 0, "draw": 0, "away": 0,
        "home_bookie": "", "draw_bookie": "", "away_bookie": ""
    }

    for slug in bookmaker_odds:
        if target_bookies and slug not in target_bookies:
            continue

        markets = bookmaker_odds[slug].get("markets", {})
        if "101" not in markets:
            continue

        outcomes = markets["101"]["outcomes"]

        home = outcomes.get("101", {}).get("players", {}).get("0", {}).get("price", 0)
        draw = outcomes.get("102", {}).get("players", {}).get("0", {}).get("price", 0)
        away = outcomes.get("103", {}).get("players", {}).get("0", {}).get("price", 0)

        if home and home > best["home"]:
            best["home"] = home
            best["home_bookie"] = slug
        if draw and draw > best["draw"]:
            best["draw"] = draw
            best["draw_bookie"] = slug
        if away and away > best["away"]:
            best["away"] = away
            best["away_bookie"] = slug

    return best

def calculate_arb(home, draw, away):
    """Calculate arbitrage opportunity."""
    total = (1/home) + (1/draw) + (1/away)
    profit = (1 - total) * 100 if total < 1 else 0
    return total, profit

# Brazilian bookmakers to compare
BRAZILIAN_BOOKIES = [
    "estrelabet", "stake.bet.br", "sportingbet.bet.br",
    "superbet.bet.br", "kto", "pinnacle"
]

# Run the scanner
print("=== Brazilian Bookmaker Arbitrage Scanner ===\n")

fixtures = get_brazil_fixtures()
print(f"Scanning {len(fixtures)} Brazilian fixtures...\n")

arb_count = 0
for f in fixtures:
    best = get_best_odds(f["fixtureId"], BRAZILIAN_BOOKIES)

    if not best or best["home"] == 0:
        continue

    total, profit = calculate_arb(best["home"], best["draw"], best["away"])

    if profit > 0:
        arb_count += 1
        print(f"🚨 ARB FOUND: {f['participant1Name']} vs {f['participant2Name']}")
        print(f"   Home: {best['home']:.2f} @ {best['home_bookie']}")
        print(f"   Draw: {best['draw']:.2f} @ {best['draw_bookie']}")
        print(f"   Away: {best['away']:.2f} @ {best['away_bookie']}")
        print(f"   Profit: {profit:.2f}%\n")

print(f"Scan complete. Found {arb_count} arbitrage opportunities.")

Bonus: Value Bet Detection (Soft vs. Sharp)

Arbitrage is rare. Value betting is more realistic. The idea: compare soft book odds (EstrelaBet, Stake BR) against Pinnacle (the sharp benchmark). When soft odds exceed sharp by a meaningful margin, you've found value.

def find_value_bets(fixture_id, soft_bookies, threshold=2.0):
    """
    Find value bets by comparing soft books vs Pinnacle.

    Args:
        fixture_id: The fixture to analyze
        soft_bookies: List of soft bookmaker slugs
        threshold: Minimum edge % to flag as value (default 2%)

    Returns:
        List of value bet opportunities
    """
    response = requests.get(f"{BASE_URL}/odds", params={
        "apiKey": API_KEY,
        "fixtureId": fixture_id
    })

    if response.status_code != 200:
        return []

    bookmaker_odds = response.json().get("bookmakerOdds", {})

    # Get Pinnacle (sharp) prices
    if "pinnacle" not in bookmaker_odds:
        return []

    sharp_markets = bookmaker_odds["pinnacle"].get("markets", {})
    if "101" not in sharp_markets:
        return []

    sharp = sharp_markets["101"]["outcomes"]
    sharp_prices = {
        "home": sharp.get("101", {}).get("players", {}).get("0", {}).get("price", 0),
        "draw": sharp.get("102", {}).get("players", {}).get("0", {}).get("price", 0),
        "away": sharp.get("103", {}).get("players", {}).get("0", {}).get("price", 0)
    }

    value_bets = []

    for soft_slug in soft_bookies:
        if soft_slug not in bookmaker_odds:
            continue

        soft_markets = bookmaker_odds[soft_slug].get("markets", {})
        if "101" not in soft_markets:
            continue

        soft = soft_markets["101"]["outcomes"]

        for outcome_id, outcome_name in [("101", "home"), ("102", "draw"), ("103", "away")]:
            soft_price = soft.get(outcome_id, {}).get("players", {}).get("0", {}).get("price", 0)
            sharp_price = sharp_prices[outcome_name]

            if soft_price > 0 and sharp_price > 0:
                edge = ((soft_price / sharp_price) - 1) * 100

                if edge >= threshold:
                    value_bets.append({
                        "outcome": outcome_name,
                        "soft_bookie": soft_slug,
                        "soft_price": soft_price,
                        "sharp_price": sharp_price,
                        "edge": edge
                    })

    return value_bets

# Find value bets
SOFT_BOOKIES = ["estrelabet", "stake.bet.br", "sportingbet.bet.br", "superbet.bet.br"]

print("=== Value Bet Scanner: Soft Books vs Pinnacle ===\n")

for f in fixtures[:20]:
    value_bets = find_value_bets(f["fixtureId"], SOFT_BOOKIES, threshold=3.0)

    if value_bets:
        print(f"{f['participant1Name']} vs {f['participant2Name']}")
        for vb in value_bets:
            print(f"   {vb['outcome'].upper()}: {vb['soft_bookie']} @ {vb['soft_price']:.2f}")
            print(f"   vs Pinnacle @ {vb['sharp_price']:.2f} (+{vb['edge']:.1f}% edge)")
        print()

Why OddsPapi for Brazilian Markets?

Three reasons this matters for Brazilian market developers:

1. 300+ Bookmakers in One API
The-Odds-API covers about 40 bookmakers. OddsPapi covers 300+, including every major Brazilian operator plus global sharps like Pinnacle and Singbet for value detection.

2. Free Historical Data
Want to backtest your Brasileirão model? Other providers charge hundreds per month for historical odds. OddsPapi includes it on the free tier.

3. Real-Time WebSockets
For live arbitrage, polling isn't fast enough. OddsPapi offers WebSocket connections for real-time odds updates during matches.

Get Started

Stop scraping. Stop paying enterprise rates for incomplete data. Get your free API key and access every Brazilian bookmaker in one call.

Get Your Free OddsPapi API Key →