Skip to main content

Python SDK for parlay-api.com — drop-in replacement for the-odds-api with player props, prediction markets, and WebSocket streaming.

Project description

parlay-api

Python SDK for parlay-api.com, a drop-in replacement for the-odds-api.com with 22 sources, player props, prediction markets, and WebSocket streaming.

pip install parlay-api
from parlay_api import ParlayAPI

client = ParlayAPI(api_key="YOUR_KEY")
events = client.odds("baseball_mlb", regions="us", markets="h2h,spreads,totals")

Why

The-odds-api is fine but ships flat -115/-115 placeholders for half the props you actually want, costs 5 to 6 times more at the Enterprise tier, and has no streaming. ParlayAPI ships real American odds across 22 sources, integrates Polymarket as a sharp prediction-market baseline, and runs WebSockets on Business+ tiers.

The SDK preserves TOA's endpoint shape, so migration is one config change.

Migration from the-odds-api

If you're currently using the unofficial Python client:

# before
from the_odds_api import OddsAPI
client = OddsAPI(api_key=KEY)
events = client.get_odds(sport_key="basketball_nba", ...)

# after, three-line diff
from parlay_api import ParlayAPI
client = ParlayAPI(api_key=KEY)
events = client.odds("basketball_nba", ...)

If you're calling TOA via raw HTTP, just swap the base URL:

# before
url = "https://api.the-odds-api.com/v4/sports/basketball_nba/odds"

# after
url = "https://parlay-api.com/v4/sports/basketball_nba/odds"

Same paths (/v4/sports, /v4/sports/{sport}/odds, /v4/sports/{sport}/events, /v4/sports/{sport}/scores, /v4/historical/sports/{sport}/odds), same response shapes, same query parameters (regions, markets, bookmakers, oddsFormat, dateFormat, eventIds, commenceTimeFrom, commenceTimeTo).

What's different from TOA

Beyond TOA's endpoints, ParlayAPI exposes:

Endpoint What
GET /v1/sports/{sport}/props Flat list of paired O/U player props across every source
GET /v1/sports/{sport}/props/markets Available prop market keys + which books offer each
GET /v1/sports/{sport}/futures Outrights and championship futures grouped by competition
GET /v1/usage Current API key usage state (tier, credits used, credits remaining)
WSS /ws/odds/{sport}?apiKey= Live odds stream, Business+ tier

Plus markets=player_* works on the standard /v4/sports/{sport}/odds endpoint, returning paired Over/Under in TOA's exact event shape.

Quickstart

from parlay_api import ParlayAPI

client = ParlayAPI(api_key="YOUR_KEY")

# List sports
print([s["key"] for s in client.sports()])

# h2h + spreads + totals across every book
events = client.odds(
    "basketball_nba",
    regions="us",
    markets="h2h,spreads,totals",
    odds_format="american",
)

# Player props (TOA-shaped)
prop_events = client.odds(
    "baseball_mlb",
    markets="player_strikeouts,player_total_bases,player_hits",
)

# Player props (flat list, ParlayAPI-extension)
rows = client.props(
    "baseball_mlb",
    markets=["player_strikeouts"],
    bookmakers=["draftkings", "pinnacle", "fanduel", "bet365"],
)
for r in rows[:10]:
    print(r["bookmaker"], r["player_name"], r["line"], r["over_price"], "/", r["under_price"])

# Devig a paired market on the client side, no network
fair_over, fair_under = ParlayAPI.devig(over_price=-110, under_price=-110)
# fair_over == 0.5, fair_under == 0.5

# Compute a +EV edge in percentage points
edge = ParlayAPI.edge(book_price=+120, fair_prob=0.55)
# +9.5pp positive expected value

WebSocket streaming (Business+)

pip install parlay-api[ws]
import asyncio, json, websockets
from parlay_api import ParlayAPI

client = ParlayAPI(api_key="YOUR_KEY")

async def run():
    async with websockets.connect(client.websocket_url("baseball_mlb")) as ws:
        while True:
            msg = json.loads(await ws.recv())
            print(msg.get("type"), len(msg.get("data") or []))

asyncio.run(run())

You'll receive an initial snapshot frame (type=odds_update with the full current state) followed by push frames whenever any book updates a price. Optional event-level filter:

await ws.send(json.dumps({
    "type": "subscribe",
    "event_id": "2026-04-29_New_York_Yankees_Boston_Red_Sox",
}))

Examples

The examples/ folder ships three runnable scripts:

  • ev_scanner.py — pulls a sport's player props, devigs the sharpest book in each market as the fair-price baseline, and prints every other book's posted line that exceeds a +3pp edge threshold. This is the basic shape of a +EV scanner.
  • arb_finder.py — scans h2h game lines across every book in the response for any pair where combined implied probability is under 100%. Computes the optimal stake split for a given bankroll. Risk-free profit when an arb exists.
  • websocket_stream.py — subscribes to the live odds WebSocket for a sport and prints diff frames as they arrive.

Run any of them after setting PARLAY_API_KEY:

export PARLAY_API_KEY=your_key
cd examples
python ev_scanner.py baseball_mlb player_strikeouts --edge 3.0
python arb_finder.py basketball_nba --bankroll 1000
python websocket_stream.py icehockey_nhl

Devig math

The SDK includes the four standard devig methods so you don't have to reimplement them:

ParlayAPI.american_to_implied(-110)   # 0.5238
ParlayAPI.american_to_decimal(-110)   # 1.9091
ParlayAPI.decimal_to_american(2.10)   # 110
ParlayAPI.implied_to_american(0.55)   # -122

# Devig with three different methods:
ParlayAPI.devig(-110, -110, method="multiplicative")  # standard
ParlayAPI.devig(-110, -110, method="additive")        # less accurate
ParlayAPI.devig(-1500, +700, method="power")          # better for skewed

Error handling

from parlay_api import (
    ParlayAPI,
    ParlayAPIError,
    InvalidAPIKeyError,
    CreditLimitExceededError,
    RateLimitedError,
    TierGatedError,
)

client = ParlayAPI(api_key="...")
try:
    events = client.odds("basketball_nba")
except CreditLimitExceededError:
    print("hit monthly credit cap")
except RateLimitedError:
    print("slow down, retry in 1s")
except TierGatedError:
    print("upgrade required for this feature")
except InvalidAPIKeyError:
    print("API key revoked or wrong")
except ParlayAPIError as e:
    print("other error:", e)

After every successful call the SDK exposes the credit headers via client.last_quota:

client.odds("basketball_nba")
print(client.last_quota.requests_remaining)  # int

Pricing

Tier $/month Credits/month Rate limit WebSocket
Free $0 1,000 10 req/s no
Starter $5 20,000 30 req/s no
Pro $20 100,000 60 req/s no
Business $40 1,000,000 100 req/s yes
Enterprise $100 5,000,000 200 req/s yes
Scale $200 50,000,000 500 req/s yes

Sign up at parlay-api.com.

License

MIT. See LICENSE.

Bugs and support

github.com/JacobiusMakes/parlay-api-python/issues or email peakpotentialmediaventures@gmail.com.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

parlay_api-0.1.0.tar.gz (12.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

parlay_api-0.1.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file parlay_api-0.1.0.tar.gz.

File metadata

  • Download URL: parlay_api-0.1.0.tar.gz
  • Upload date:
  • Size: 12.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for parlay_api-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d2904987b45ff6f4526f11fcde3a07c30994d410c62cc5d5d5ff1f652af0efe2
MD5 1bdb3fab9f5b9ebc0e63822229c291c4
BLAKE2b-256 b2e95b0e8d7bfef2cdf4971d24e0cb26e0d9bd963eb50ff3f07fd4066bcdf88d

See more details on using hashes here.

File details

Details for the file parlay_api-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: parlay_api-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for parlay_api-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 23343a08c02a3de0fa14988160c2e51b67fc34f7a1f551acebc6bc4eb098dac0
MD5 fb5c03aa08f6b63c586d9cd986941831
BLAKE2b-256 90ee236bd5d40420a1612d00cb0e0112b7a771ef308a08f2c37992a61b67850a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page