OSopensport.dev
Reference

Providers

A Provider fetches events and odds from a data source and normalises them into the core models. Opensport ships six built-in providers. Swap any without changing your agent code.

Overview

ProviderCoverageAPI keyInstall extra
MockProviderIn-memory, deterministic, no networkNoneNone
PremierLeagueProviderEnglish Premier League (fixtures + odds)2 × freeopensport[http]
MasseyRatingsProviderNFL · NBA · MLB · NHL · NCAAF · NCAABNoneopensport[massey]
StakeProvider20+ sports + esportsRequiredopensport[http]
CloudbetProvider20+ sports (free affiliate key)Required (free)opensport[http]
PolymarketProvider10+ sports (prediction market prices)Noneopensport[http]

ProviderRegistry + MultiProvider

Use ProviderRegistry to track which providers are active, and MultiProvider to expose them all through a single BaseProvider interface, with no agent changes required.

Auto-discover from environment variables

from opensport.providers import ProviderRegistry, MultiProvider

registry = ProviderRegistry.from_env()
# Activates providers based on which env vars are set:
#   FOOTBALL_DATA_API_KEY + ODDS_API_KEY  → PremierLeagueProvider
#   MASSEY_SPORTS=nfl,nba (or "all")      → MasseyRatingsProvider
#   STAKE_API_KEY                          → StakeProvider
#   CLOUDBET_API_KEY                       → CloudbetProvider
#   POLYMARKET_ENABLED=1                   → PolymarketProvider

provider = MultiProvider(registry)
events = provider.get_events(sport="soccer")

Build manually

from opensport.providers import ProviderRegistry, MultiProvider
from opensport.providers.mock import MockProvider
from opensport.providers.football_data import PremierLeagueProvider
from opensport.providers.massey import MasseyRatingsProvider
from opensport.providers.stake import StakeProvider
from opensport.providers.cloudbet import CloudbetProvider
from opensport.providers.polymarket import PolymarketProvider

registry = (
    ProviderRegistry()
    .register(MockProvider())
    .register(PremierLeagueProvider(fbd_api_key="...", odds_api_key="..."))
    .register(MasseyRatingsProvider(sports=["nfl", "nba"]))
    .register(StakeProvider(api_key="..."))
    .register(CloudbetProvider(api_key="..."))
    .register(PolymarketProvider(min_liquidity=500.0))
)

# Enable / disable at runtime
registry.disable("mock")
registry.enable("mock")

# Inspect state
for row in registry.status():
    print(row["name"], "→", "ON" if row["enabled"] else "OFF")

# Wire into an agent (unchanged interface)
provider = MultiProvider(registry)
agent = ValueAgent(provider=provider, execution=Simulator(bankroll=1000))

MultiProvider merges get_events() across all active providers and routes get_odds(event_id) to the correct provider via the event ID prefix. Provider failures are logged as warnings and skipped. They do not propagate.

MockProvider

Fully in-memory provider with deterministic output controlled by a seed. No API keys, no network calls. Use it for unit testing, tutorials, and sandboxing new strategies.

pip install opensport    # zero extra dependencies
from opensport.providers.mock import MockProvider

provider = MockProvider(seed=42)
events   = provider.get_events()
snap     = provider.get_odds(events[0].id)
ParameterDefaultDescription
seed0Integer seed for reproducible event and odds generation
sportsallList of sport slugs to generate events for
n_events_per_sport5Number of events to generate per sport

PremierLeagueProvider

English Premier League fixtures, scores, and match-winner odds. Combines two free APIs: Football-Data.org for fixture data and The Odds API for odds. Both offer generous free tiers.

pip install 'opensport[http]'
from opensport.providers.football_data import PremierLeagueProvider

provider = PremierLeagueProvider(
    fbd_api_key="your-football-data-key",
    odds_api_key="your-odds-api-key",
)

events = provider.get_events()
snap   = provider.get_odds(events[0].id)

# Auto-activate via environment variables:
#   FOOTBALL_DATA_API_KEY=...
#   ODDS_API_KEY=...
ParameterDescription
fbd_api_keyFootball-Data.org API key (free tier: 10 req/min)
odds_api_keyThe Odds API key (free tier: 500 req/month)
timeoutHTTP timeout in seconds (default: 10.0)

MasseyRatingsProvider

Schedules, scores, and model-derived win-probability odds for the major US sports leagues: NFL, NBA, MLB, NHL, NCAA Football, and NCAA Basketball. No API key required. Data is sourced from masseyratings.com.

pip install 'opensport[massey]'
from opensport.providers.massey import MasseyRatingsProvider

provider = MasseyRatingsProvider(sports=["nfl", "nba", "mlb", "nhl"])

events = provider.get_events(sport="nfl")
snap   = provider.get_odds(events[0].id)

# Auto-activate via environment variable:
#   MASSEY_SPORTS=nfl,nba     (comma-separated slugs)
#   MASSEY_SPORTS=all         (every supported sport)
ParameterDefaultDescription
sportsRequiredList of slugs: nfl, nba, mlb, nhl, ncaaf, ncaab
timeout15.0HTTP timeout in seconds

StakeProvider

Live bookmaker odds from Stake.com across 20+ sports and esports. Requires a Stake API key.

pip install 'opensport[http]'
from opensport.providers.stake import StakeProvider

provider = StakeProvider(
    api_key="your-stake-api-key",
    sports=["soccer", "basketball"],   # None = all available sports
)

events = provider.get_events(sport="soccer")
snap   = provider.get_odds(events[0].id)

# Auto-activate via environment variables:
#   STAKE_API_KEY=...
#   STAKE_SPORTS=soccer,basketball   (optional)
ParameterDefaultDescription
api_keyRequiredStake.com API key
sportsNoneList of sport slugs to fetch. None = all sports.
timeout10.0HTTP timeout in seconds

CloudbetProvider

Real bookmaker odds from Cloudbet.com across 20+ sports. A free affiliate API key is available. No deposit required.

pip install 'opensport[http]'
from opensport.providers.cloudbet import CloudbetProvider

provider = CloudbetProvider(
    api_key="your-cloudbet-api-key",
    sports=["soccer", "basketball"],   # None = all available sports
)

events = provider.get_events(sport="soccer")
snap   = provider.get_odds(events[0].id)

# Auto-activate via environment variables:
#   CLOUDBET_API_KEY=...
#   CLOUDBET_SPORTS=soccer,basketball   (optional)
ParameterDefaultDescription
api_keyRequiredCloudbet API key (free affiliate key available)
sportsNoneList of sport slugs to fetch. None = all sports.
timeout10.0HTTP timeout in seconds

PolymarketProvider

Consensus probabilities from Polymarket, the world's largest decentralised prediction market. No API key required. Prices reflect the crowd's implied probability rather than a bookmaker's margin-adjusted odds, making them useful as a reference signal for detecting value in traditional bookmaker lines.

pip install 'opensport[http]'
from opensport.providers.polymarket import PolymarketProvider

# No API key required (explicit opt-in only)
provider = PolymarketProvider(
    sports=["basketball", "soccer"],   # None = all supported sports
    min_liquidity=500.0,               # skip thin markets (USDC)
)

events = provider.get_events(sport="basketball")
snap   = provider.get_odds(events[0].id)
winner = snap.market("winner")
if winner:
    for o in winner.outcomes:
        print(f"  {o.label}: {o.decimal_odds:.2f}  ({100/o.decimal_odds:.1f}% implied)")

# Auto-activate via environment variables:
#   POLYMARKET_ENABLED=1
#   POLYMARKET_SPORTS=basketball,soccer   (optional)
#   POLYMARKET_MIN_LIQUIDITY=500          (optional USDC floor)
ParameterDefaultDescription
sportsNoneList of sport slugs. None = all supported sports.
min_liquidity0.0Skip markets with less than this USDC liquidity.
timeout10.0HTTP timeout in seconds.

Prices are probabilities (0–1) converted to decimal odds: decimal_odds = 1 / probability. Because there is no bookmaker margin, both outcomes in a binary market sum to approximately 1.0.

Supported sport slugs: soccer, basketball, american-football, baseball, ice-hockey, tennis, cricket, mma, boxing. Unknown slugs are passed through as Polymarket native tag slugs (e.g. ncaab, primera-a).

Building a custom provider

Subclass BaseProvider, implement get_events() and get_odds(), and map your data source's native objects into the core models. See the Architecture guide for a full skeleton example.

from opensport.providers.base import BaseProvider
from opensport.core.event import Event
from opensport.core.odds import OddsSnapshot

class MyProvider(BaseProvider):
    name = "my_provider"           # unique name for registry routing
    event_id_prefix = "myprov-"   # used by MultiProvider to route get_odds()

    def get_events(self, sport=None, competition=None, status=None) -> list[Event]:
        ...  # fetch raw data and return list[Event]

    def get_odds(self, event_id: str) -> OddsSnapshot:
        ...  # fetch and return OddsSnapshot