A live odds API delivers in-play betting lines as they change during a sporting event. Every time a goal is scored, a player fouls out, or momentum shifts in a match, bookmakers adjust their prices. A live odds feed pushes those updated prices to your application in near real-time, giving you the same data that powers professional sportsbooks and trading desks.
If you are building an odds comparison site, a live betting dashboard, or an automated trading system, you need a live odds API. This guide covers how live odds data works, which providers offer the best real-time feeds, and how to integrate them into your application with working code. For broader context on how sports betting data flows from bookmakers to your app, see our complete sports betting API guide.
What Is a Live Odds API?
A live odds API is a programmatic interface that returns current betting lines for events that are already in progress. Unlike pre-match odds that are set hours or days before an event, live odds shift continuously throughout a game based on what is happening on the field, court, or pitch.
The API typically returns structured JSON containing the event ID, current scores, available markets (moneyline, spread, totals), and the latest prices from multiple bookmakers. Your application polls the endpoint at regular intervals or opens a persistent streaming connection to receive updates the moment lines move.
Live odds data is the foundation of in-play betting, which now accounts for a significant share of total sports wagering volume worldwide. The speed and reliability of your live odds feed directly impacts the quality of your product.
Pre-Match vs In-Play Data
Pre-match and in-play odds come from the same bookmakers, but they behave differently in every way that matters for integration.
Pre-match odds are relatively stable. A bookmaker might adjust the moneyline on an NFL game a few times per day in the days leading up to kickoff. You can poll a pre-match endpoint every 10 to 15 minutes and capture nearly every line movement. The data changes slowly, rate limits are rarely an issue, and caching works well.
In-play odds are volatile. During a live NBA game, the spread can shift multiple times per minute after a scoring run, a key player picking up their fourth foul, or a timeout being called. Lines on some markets may be suspended entirely during active play and reopened seconds later with new prices. The data changes rapidly, and stale prices create problems. An odds comparison site showing a line that moved 30 seconds ago will frustrate users. An arbitrage scanner working on stale data will flag opportunities that no longer exist.
The practical difference for developers is this: pre-match data works fine with infrequent REST polling. In-play data demands either fast polling intervals (every 5 to 30 seconds) or a streaming connection that pushes updates as they happen. Choose your delivery method based on how your application uses the data.
Update Frequency and Latency
Latency is the time between a bookmaker changing a line and your application receiving that new price. For live odds, latency ranges from under one second (with WebSocket or SSE streaming) to 30 seconds or more (with REST polling at conservative intervals).
Here is how the numbers break down by delivery method:
- WebSocket or SSE streaming: sub-second to 2 seconds. The server pushes new data the moment it detects a line change. No wasted requests, no polling delay.
- Fast REST polling (every 5 seconds): 5 to 10 second average latency. You will catch most movements quickly, but you are always behind by at least one polling interval.
- Standard REST polling (every 30 seconds): 15 to 30 second average latency. Acceptable for display purposes on comparison sites, but too slow for automated trading or alerting.
- Slow REST polling (every 60+ seconds): not suitable for live odds. By the time you receive the data, it may already be outdated.
The right latency target depends on your use case. A content site displaying live lines for editorial purposes can tolerate 30-second delays. A system that executes bets based on line discrepancies needs sub-second delivery. Most applications fall somewhere in between, and a 5 to 15 second refresh cycle covers the majority of live odds use cases.
Best Live Odds API Providers
Three providers stand out for live odds data, each serving a different segment of the market. For a broader comparison across all use cases, see our full provider comparison.
The Odds API
The Odds API is the most popular choice for developers who want a straightforward REST endpoint for live and pre-match odds. It aggregates odds from dozens of bookmakers and returns them in clean JSON with a single request.
Live events are identified by comparing the commence_time field against the current time. If commence_time is in the past, the event is in-play. The /odds endpoint returns both upcoming and live events in the same response, so you filter client-side.
Key details for live odds integration:
- Delivery: REST API (no native WebSocket). You poll the endpoint at your desired interval.
- Update frequency: live scores update approximately every 30 seconds. Odds data follows a similar cadence.
- Rate limit: 30 requests per second across all plans.
- Free tier: 500 requests per month. Paid plans start at $20/month (20,000 requests) and go up to $199/month (12,000,000 requests).
- Quota cost: each
/oddsrequest costs 1 credit per region per market. Combine markets in a single request to conserve credits. - Response includes: event ID, teams, commence time, bookmaker names, and odds for each market.
The Odds API is a strong choice if you want to get live odds running quickly without managing WebSocket connections. The REST-only approach is simpler to implement and debug. The trade-off is higher latency compared to streaming providers. If you are new to odds APIs in general, our Python tutorial walks through setup step by step.
OpticOdds
OpticOdds targets professional bettors and trading operations that need the fastest possible data delivery. The platform processes over 1 million odds updates per second across hundreds of servers.
What sets OpticOdds apart is its Server-Sent Events (SSE) streaming endpoint. Instead of polling, you open a persistent HTTP connection and receive odds updates as they happen. The stream pushes two event types: odds for live price updates and locked-odds when markets are suspended.
Key details:
- Delivery: REST API plus SSE streaming at
GET /api/v3/stream/odds/{sport}. - Streaming parameters: filter by sportsbook, market, and fixture ID. Use
last_entry_idto resume a disconnected stream without missing updates. - Rate limits: 10 requests per 15 seconds for historical endpoints. 250 requests per 15 seconds for streaming endpoints.
- Coverage: 80+ sportsbooks, all major sports, player props, and alternate lines.
- Authentication: API key passed via
X-Api-Keyheader orkeyquery parameter. - Results stream: a separate SSE endpoint at
/api/v3/stream/results/{sport}delivers live scores, period results, and game status changes.
OpticOdds is the provider to choose when latency matters most. The SSE streaming model eliminates polling delay entirely, and the filtering parameters let you subscribe only to the markets you care about, keeping bandwidth low.
Sportradar
Sportradar serves the enterprise tier of the market. Their Odds Comparison Live Odds API delivers in-game odds across major sports and bookmakers with updates every 15 to 30 seconds.
Key details:
- Delivery: REST API plus Push feeds for real-time streaming.
- Update frequency: 15 to 30 seconds for REST. Push feeds deliver lower-latency updates.
- Coverage: event lines, spreads, totals, and live player props. Uses the same SRID-based structure as other Sportradar APIs for easy cross-product mapping.
- Endpoints: daily event schedules, competition-level markets, individual event markets, player props, and ID mapping endpoints.
- Access: enterprise pricing. No self-service trial; contact their sales team for access.
Sportradar is built for operators running licensed sportsbooks, major media platforms, or large-scale data products. If you are an individual developer or small team, The Odds API or OpticOdds will be more accessible both in pricing and onboarding.
Integration Guide
Connecting to a live odds API comes down to two architectural choices: how you receive the data (polling vs streaming) and how you handle the constraints of each approach (rate limits, reconnection, caching).
REST Polling vs WebSocket Streaming
REST polling means your application sends an HTTP GET request to the odds endpoint at regular intervals. Each request returns the full current state of all live events. This is the simpler approach and works with any HTTP client in any language.
WebSocket (or SSE) streaming means your application opens a single persistent connection. The server pushes new data through that connection whenever odds change. You receive only the deltas, not the full state on every update.
Here is a direct comparison:
- Latency: Polling adds at least one interval of delay (if you poll every 10 seconds, you are 0 to 10 seconds behind). Streaming delivers updates within 1 to 2 seconds.
- Bandwidth: Polling transfers the full response every time, even if nothing changed. Streaming only sends data when odds actually move, using significantly less bandwidth.
- Rate limits: Every poll consumes an API request from your quota. Streaming connections typically do not count against request limits once established.
- Complexity: Polling requires only an HTTP client and a timer. Streaming requires handling connection drops, reconnection logic, heartbeat monitoring, and state management.
- Reliability: Polling is inherently resilient. If a request fails, you try again next interval. Streaming requires explicit reconnection handling and gap detection (using
last_entry_idor similar mechanisms).
For most applications, start with REST polling. It is easier to build, test, and debug. Move to streaming when polling latency becomes a bottleneck or your request volume pushes against rate limits.
Setting Up Polling
A well-built polling loop follows this pattern:
- Make a request to the live odds endpoint.
- Parse the response and update your local data store.
- Check the rate limit headers to confirm you have quota remaining.
- Wait for the polling interval to elapse.
- Repeat.
The polling interval should match your use case. For a content site, 30 seconds is reasonable. For a live dashboard, 10 seconds strikes a balance between freshness and API consumption. For anything faster than 5 seconds, you should seriously consider switching to a streaming endpoint instead.
Here is a minimal Python example using The Odds API:
import requests
import time
import os
API_KEY = os.environ.get("ODDS_API_KEY")
SPORT = "basketball_nba"
REGIONS = "us"
MARKETS = "h2h,spreads,totals"
POLL_INTERVAL = 30
url = f"https://api.the-odds-api.com/v4/sports/{SPORT}/odds"
params = {
"apiKey": API_KEY,
"regions": REGIONS,
"markets": MARKETS,
}
while True:
response = requests.get(url, params=params)
if response.status_code == 200:
events = response.json()
remaining = response.headers.get("x-requests-remaining")
print(f"Got {len(events)} events | Requests remaining: {remaining}")
for event in events:
print(f" {event['away_team']} @ {event['home_team']}")
elif response.status_code == 429:
print("Rate limited. Waiting 5 seconds...")
time.sleep(5)
continue
else:
print(f"Error: {response.status_code}")
time.sleep(POLL_INTERVAL)
This loop runs indefinitely, fetching NBA odds every 30 seconds. The x-requests-remaining header tells you exactly how much quota you have left. If you hit a 429, the loop waits 5 seconds before retrying.
Handling Rate Limits
Every live odds provider enforces rate limits. Exceeding them returns a 429 Too Many Requests response and may temporarily block your API key. Here is how to stay within bounds:
- Combine markets in a single request. Fetching
h2h,spreads,totalsin one call costs 3 credits but saves 2 requests compared to fetching each market separately. With The Odds API, a single request can include multiple markets and regions. - Cache metadata. Endpoints like
/sportsor/eventschange infrequently. Cache their responses for an hour and avoid hitting the API for data that has not changed. - Use conditional polling. Before making a request, check whether there are actually live events happening. If no games are in progress, skip the poll or extend the interval to 5 minutes.
- Implement exponential backoff. When you receive a 429, do not immediately retry. Wait 2 seconds, then 4, then 8, up to a maximum of 60 seconds. Many APIs include a
Retry-Afterheader that tells you exactly how long to wait. - Monitor your usage. Track the
x-requests-remainingandx-requests-usedheaders on every response. Set an alert when usage exceeds 80% of your monthly quota.
import time
def fetch_with_backoff(url, params, max_retries=5):
delay = 2
for attempt in range(max_retries):
response = requests.get(url, params=params)
if response.status_code == 200:
return response
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", delay))
print(f"Rate limited. Retrying in {retry_after}s...")
time.sleep(retry_after)
delay = min(delay * 2, 60)
else:
response.raise_for_status()
return None
This helper function wraps your API call with automatic backoff. It respects the Retry-After header when present and doubles the delay on each consecutive failure up to a 60-second cap.
Code Example: Stream Live NBA Odds
Here is a complete working example that polls live NBA odds every 30 seconds, filters for in-play games only, and displays the latest lines in a readable format. This uses The Odds API, which is the easiest provider to get started with.
import requests
import time
import os
from datetime import datetime, timezone
API_KEY = os.environ.get("ODDS_API_KEY")
SPORT = "basketball_nba"
REGIONS = "us"
MARKETS = "h2h,spreads,totals"
POLL_INTERVAL = 30
def fetch_live_odds():
url = f"https://api.the-odds-api.com/v4/sports/{SPORT}/odds"
params = {
"apiKey": API_KEY,
"regions": REGIONS,
"markets": MARKETS,
"oddsFormat": "american",
}
response = requests.get(url, params=params)
if response.status_code == 429:
retry = int(response.headers.get("Retry-After", 5))
print(f"Rate limited. Waiting {retry}s...")
time.sleep(retry)
return []
if response.status_code != 200:
print(f"Error {response.status_code}: {response.text[:200]}")
return []
remaining = response.headers.get("x-requests-remaining", "?")
print(f"API requests remaining: {remaining}")
return response.json()
def is_live(event):
commence = datetime.fromisoformat(
event["commence_time"].replace("Z", "+00:00")
)
return commence < datetime.now(timezone.utc)
def display_odds(event):
home = event["home_team"]
away = event["away_team"]
print(f"\n {away} @ {home} (LIVE)")
for bookmaker in event.get("bookmakers", [])[:3]:
book_name = bookmaker["title"]
for market in bookmaker.get("markets", []):
key = market["key"]
outcomes = market["outcomes"]
if key == "h2h":
prices = {o["name"]: o["price"] for o in outcomes}
away_price = prices.get(away, "N/A")
home_price = prices.get(home, "N/A")
print(f" {book_name} | ML: {away} {away_price} / {home} {home_price}")
elif key == "spreads":
for o in outcomes:
if o["name"] == home:
print(f" {book_name} | Spread: {home} {o.get('point', '')} ({o['price']})")
elif key == "totals":
for o in outcomes:
if o["name"] == "Over":
print(f" {book_name} | Total: O/U {o.get('point', '')} ({o['price']})")
def main():
print("Polling live NBA odds every 30 seconds...")
print("Press Ctrl+C to stop.\n")
while True:
now = datetime.now().strftime("%H:%M:%S")
print(f"--- Fetching odds at {now} ---")
events = fetch_live_odds()
live_events = [e for e in events if is_live(e)]
if live_events:
print(f"Found {len(live_events)} live game(s):")
for event in live_events:
display_odds(event)
else:
print("No live NBA games right now.")
print(f"\nNext poll in {POLL_INTERVAL}s...\n")
time.sleep(POLL_INTERVAL)
if __name__ == "__main__":
main()
To run this script:
- Get a free API key from the-odds-api.com
- Set your key as an environment variable:
export ODDS_API_KEY="your_key_here" - Install the requests library:
pip install requests - Run the script:
python live_nba_odds.py
The script will print live games with moneyline, spread, and totals from the first three bookmakers in each response. It handles rate limiting automatically with the Retry-After header and displays your remaining API quota on every poll.
You can adapt this example to any sport by changing the SPORT variable. The Odds API uses sport keys like americanfootball_nfl, baseball_mlb, soccer_epl, and icehockey_nhl. The full list is available from the /sports endpoint.
FAQ
How fast do live odds update?
Update speed depends on the provider and delivery method. With WebSocket or SSE streaming from a provider like OpticOdds, odds updates arrive within 1 to 2 seconds of the bookmaker changing the line. With REST polling, your effective update speed equals your polling interval. Polling every 10 seconds means you are 0 to 10 seconds behind the actual market. Sportradar’s REST endpoints refresh every 15 to 30 seconds. The Odds API live scores update approximately every 30 seconds. For most live betting displays, a 10 to 30 second refresh cycle is sufficient.
Which API has the lowest latency?
OpticOdds offers the lowest latency for developers who need near-instant updates. Their SSE streaming endpoint pushes odds changes as they happen, with sub-second delivery in most cases. Their infrastructure processes over 1 million odds per second. For developers who prefer REST polling and want the simplest integration, The Odds API delivers reliable data with a 30 requests per second rate limit, though you are limited to the latency of your polling interval. Sportradar’s Push feeds also offer low-latency streaming, but access requires enterprise-level contracts.
Can I get live odds for free?
Yes, but with significant limitations. The Odds API offers a free tier with 500 requests per month. If each request costs 1 credit and you poll every 30 seconds, you will burn through your monthly quota in about 4 hours of continuous polling for a single sport. The free tier is useful for prototyping and testing your integration, but any production application that monitors live odds throughout game days will need a paid plan. Paid plans with The Odds API start at $20 per month for 20,000 requests, which supports roughly 6 to 7 hours of 30-second polling per day for one sport and market combination. For a full breakdown of pricing and features across providers, see our API comparison guide.