Python SDK
Sync and asyncio clients for Python 3.10+, with every object of the API typed. Every endpoint is a method.
Install
One package, no setup beyond your API key.
$ pip install "git+https://github.com/sportsapiapp/sportsapi-python" # until it is on PyPI $ pip install sportsapi # once it is
Authenticate
Use the API key from your dashboard. Pass it to the client, or set SPORTSAPI_API_KEY and the client reads it.
from sportsapi import SportsAPI client = SportsAPI() # reads SPORTSAPI_API_KEY (or SportsAPI(api_key="sk_live_…"))
First calls
Every method returns the API's { data, meta } envelope, typed. Path parameters come first, in path order, then the query parameters with the API's own names.
live = client.livescores.list(sport="football") for fixture in live["data"]: print(fixture["home"]["name"], fixture["homeScore"]["current"], "–", fixture["awayScore"]["current"], fixture["away"]["name"]) table = client.leagues.standings(17, season=61627)["data"]
Errors
One error type per HTTP status, each carrying the API's code, message and Retry-After. Branch on the code, never on the message.
from sportsapi import NotFoundError, PermissionDeniedError, SportsAPIError try: client.fixtures.win_probability(211521) except PermissionDeniedError as e: # 403: e.code == "endpoint_not_in_plan", … ... except NotFoundError as e: # 404: not_found, no_data, not_supported ... except SportsAPIError as e: # every error: e.status, e.code, e.message, e.retry_after ...
Paging
Every endpoint with a page parameter has a pages iterator that walks the pages until there are no more.
for page in client.teams.fixtures_pages(42, type="recent", max_pages=3): for fixture in page["data"]: ...
asyncio
AsyncSportsAPI has the same methods, awaited.
import asyncio from sportsapi import AsyncSportsAPI async def main() -> None: async with AsyncSportsAPI() as client: fixture = await client.fixtures.get(211521) print(fixture["data"]["status"]["description"]) asyncio.run(main())
WebSocket stream (Business)
The stream mints its own single-use ticket, subscribes, reconnects and replays what it missed, and merges every delta into the fixtures it holds.
with client.stream(["livescores", "fixture:211521"]) as stream: for frame in stream: if frame["type"] == "delta": print(frame["id"], frame["changes"]) in_play = stream.fixtures("livescores") # the merged state, any time
Options
A 429 rate_limited or a 503 is retried after Retry-After (twice by default); a quota error never is.
SportsAPI( api_key=..., # or SPORTSAPI_API_KEY base_url=..., # or SPORTSAPI_BASE_URL timeout=30.0, # seconds per attempt max_retries=2, )