Skip to content
datasportsAPI

PyPython SDK

Sync for scripts, asyncio for services.

Two clients with the same methods: DataSportsAPI for notebooks and scripts, AsyncDataSportsAPI for asyncio services. Every object of the contract is a typed dict, so your editor knows the field names.

Package
datasportsapi
Runs on
Python 3.10+ · sync and asyncio
Key
DATASPORTSAPI_API_KEY
Status
Not published yet
Install
$ pip install datasportsapi

The install line goes live with the first release; nothing is on a public registry yet. Everything on this page describes the client as it will ship.

  1. Install

    One package for both the sync and the asyncio client.

    shell
    $ pip install datasportsapi
    # or
    $ uv add datasportsapi
    $ poetry add datasportsapi
  2. Authenticate

    Create a key in your dashboard. With no argument the client reads DATASPORTSAPI_API_KEY; pass api_key when the key lives somewhere else.

    client.py
    from datasportsapi import DataSportsAPI
    
    client = DataSportsAPI()  # reads DATASPORTSAPI_API_KEY
    
    # or explicitly
    client = DataSportsAPI(api_key="dsa_live_…")
  3. First calls

    Methods follow the docs' grouping. Path parameters are positional, in path order; query parameters are keyword arguments with the API's own names. Each call returns the { data, meta } envelope.

    first_calls.py
    live = client.livescores.list(sport="football")
    for f in live["data"]:
        print(f["home"]["name"], f["homeScore"]["current"], "-",
              f["awayScore"]["current"], f["away"]["name"])
    
    table = client.leagues.standings(17, season=76986)["data"]
    lineups = client.fixtures.lineups(480112)["data"]
  4. Errors

    Each HTTP status raises its own exception, and every one exposes status, code, message and retry_after. Branch on code; leave the message to your logs.

    errors.py
    from datasportsapi import (
        DataSportsAPIError, NotFoundError, PermissionDeniedError, RateLimitError,
    )
    
    try:
        wp = client.fixtures.win_probability(480112)
    except PermissionDeniedError as e:   # 403
        if e.code == "endpoint_not_in_plan":
            show_upgrade_hint()
    except NotFoundError as e:           # 404: not_found, no_data, not_supported
        hide_panel()
    except RateLimitError as e:          # 429 once retries are spent
        if e.code == "quota_exceeded":
            pause_for(e.retry_after)
    except DataSportsAPIError as e:      # anything else from the API
        log.warning("%s %s", e.status, e.code)
    Python error type for each HTTP status, and the codes each status can carry
    StatusExceptionerror.code
    400BadRequestErrorbad_request
    401AuthenticationErrorunauthorized
    403PermissionDeniedErrorendpoint_not_in_planhistory_not_in_planws_not_availableorigin_not_allowedip_not_allowed
    404NotFoundErrornot_foundno_datanot_supported
    429RateLimitErrorrate_limitedquota_exceeded
    500InternalServerErrorinternal_error
    503ServiceUnavailableErrorupstream_unavailable
  5. Paging

    Endpoints that take a page parameter get a …_pages twin: a generator that requests the next page lazily and stops after the last one, or at max_pages.

    paging.py
    for page in client.teams.fixtures_pages(42, type="recent", max_pages=4):
        for fixture in page["data"]:
            archive(fixture)
  6. asyncio

    AsyncDataSportsAPI mirrors every method as a coroutine, so concurrent calls are a gather away. Use it as an async context manager to close the connection pool cleanly.

    async_client.py
    import asyncio
    from datasportsapi import AsyncDataSportsAPI
    
    async def main() -> None:
        async with AsyncDataSportsAPI() as client:
            fixture, lineups = await asyncio.gather(
                client.fixtures.get(480112),
                client.fixtures.lineups(480112),
            )
            print(fixture["data"]["status"]["description"])
    
    asyncio.run(main())
  7. WebSocket stream

    Business

    client.stream() takes care of the single-use ticket, the subscription, reconnecting and replaying after a drop, and folding each delta into the fixtures it tracks. The async client has the same stream with async for.

    stream.py
    with client.stream(["livescores", "fixture:480112"]) as stream:
        for frame in stream:
            if frame["type"] == "delta":
                print(frame["id"], frame["changes"])
            in_play = stream.fixtures("livescores")  # merged state, any time

    Channels, frames and replay rules are in the WebSocket guide. Without a Business key the stream answers 403 ws_not_available.

  8. Options

    429 rate_limited and 503 are retried after Retry-After, twice by default. 429 quota_exceeded is raised at once, because only the reset fixes it.

    options.py
    client = DataSportsAPI(
        api_key=None,     # None: DATASPORTSAPI_API_KEY
        base_url=None,    # None: DATASPORTSAPI_BASE_URL, then https://api.datasportsapi.com
        timeout=30.0,     # seconds, per attempt
        max_retries=2,    # rate_limited and 503 only
    )

    Base URL resolution: the option or flag first, then DATASPORTSAPI_BASE_URL, then https://api.datasportsapi.com.

From the endpoint pages

Every endpoint shows its Python call.

All endpoints

Other clients

Your key is one form away.

1,000 free requests a day during the beta. No card, no sales call.