Welcome to the complete guide for integrating and using BoltOdds. This documentation will help you get up and running quickly so you can access real-time sports betting odds.
Quick Start
Get connected in just a few steps:
Step 1: Obtain Your API Key
First, sign up for an account and retrieve your API key. This should be sent to the email you signed up with. You'll need this for authentication. If you dont see it in your inbox, please check your spam/junk folder.
Step 2: Establish Connection
async def run_client():
uri = "wss://spro.agency/api?key=YOUR_TOKEN"
while True:
try:
async with websockets.connect(uri) as websocket:
ack_message = await websocket.recv()
print(ack_message)
Step 3: Send Subscription Data
To see all the sports and sportsbooks you could subscribe to, see the GET request below. NOTE: sports and sportsbooks MUST be subscribed to in the exact format seen in the response from the GET request below. Any deviation will be ignored. If either of these subscription filters are left out, your subscription will default to all available options, in this case all sports and sportsbooks.
To see all the games you could subscribe to, see the GET request below. NOTE: games MUST be subscribed to in the exact format seen in the response from the GET request below. Any deviation will be ignored. If this subscription filter is left out, your subscription will default to all available options, in this case all games.
To see all the markets you could subscribe to, see the GET request below. NOTE: markets MUST be subscribed to in the exact format seen in the response from the GET request below. Any deviation will be ignored. If this subscription filter is left out, your subscription will default to all available options, in this case all markets.
You have the option to add query paramaters to this request, specifically "sportsbooks" and "sports". This allows you to specify a certain book, sport, or a combo of each where you want to see the markets available. If your request does not specify these parameters, it will return all markets for all sportsbooks and all sports. YOUR_SPORTS can be a comma-seperated string if you want to get the markets for multiple sports in one request. The same goes for YOUR_BOOKS. For example:
If you dont want to filter for a certain category, just dont include its key in your subscription filters. For example, if you dont want to specify a game(s) to sub to, dont include the 'games' key in the subscription filters.
subscribe_message = {
"action": "subscribe",
"filters": {
"sports": ["NBA", "MLB", "Wimbledon (M)"],
"sportsbooks": ["draftkings", "betmgm"],
"games":["San Francisco Giants vs Philadelphia Phillies, 2025-07-07, 09", "Corinthians vs Bragantino, 2025-07-13, 06"],
"markets":["Moneyline", "Spread"]
}
}
await websocket.send(json.dumps(subscribe_message))
# You are now connected and subscribed to your specified stream of data
while True:
message = await websocket.recv()
Authentication
All WebSocket connections must be authenticated using your API key.
Authentication Flow
- Establish WebSocket connection using a valid API key.
- Once ack_message is received, you have been validated
Connection Management
Automatic Reconnection
async def run_client():
uri = "wss://spro.agency/api?key=YOUR_TOKEN"
while True:
try:
async with websockets.connect(uri) as websocket:
ack_message = await websocket.recv()
print(ack_message)
subscribe_message = {
"action": "subscribe",
"filters": {
"sports": ["NBA", "MLB", "Wimbledon (M)"],
"sportsbooks": ["draftkings", "betmgm"],
"games":["San Francisco Giants vs Philadelphia Phillies, 2025-07-07, 09", "Corinthians vs Bragantino, 2025-07-13, 06"],
"markets":["Moneyline", "Spread"]
}
}
await websocket.send(json.dumps(subscribe_message))
# You are now connected and subscribed to your specified stream of data
while True:
message = await websocket.recv()
except websockets.ConnectionClosed as e:
print("Connection closed — reason:", e)
print('Reconnecting...')
await asyncio.sleep(5)
continue
#can add other exception handling as needed
Message Format
All messages sent through the WebSocket are JSON formatted and follow a consistent structure.
Message Types
The foundation of all messages is an action which will tell you what the message entails. These are the actions BoltOdds sends which you could expect to receive. Please note that message format can be changed or modified in the future.
- socket_connected - Initial authentication successfull
- initial_state - After subscribing, you will be sent the state of all odds at that very moment in accordance to your subscription filters
- game_update - All odds for a specific game have been updated
- game_removed - Entire game removed (finished, suspended, etc)
- line_update - A line update. If odds provided are None or '', it means there are no odds available for this line i.e its currently suspended, deleted etc
- book_clear - All games for specified book have been cleared. This may happen in the case of connection drops on our backend
- ping - Keep-alive message
{'action': 'socket_connected'}
{
"timestamp": "2025-07-23T19:45:03.048958+00:00",
"action": "initial_state",
"data": {
"sport": "MLB",
"sportsbook": "ballybet",
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"home_team": "New York Mets",
"away_team": "Los Angeles Angels",
"info": {
"id": 1022036664,
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"when": "2025-07-23, 01:09 PM",
"link": "https://play.ballybet.ca/sports#event/1022036664"
},
"outcomes": {
"New York Mets Moneyline": {
"odds": "-10000",
"link": "https://play.ballybet.ca/sports#event/1022036664?coupon=pickType|3815533797|wagerAmounts|replace", #deep link
"outcome_name": "Moneyline",
"outcome_line": null,
"outcome_over_under": null,
"outcome_target": "New York Mets"
},
"Los Angeles Angels Moneyline": {
"odds": "+3300",
"link": "https://play.ballybet.ca/sports#event/1022036664?coupon=pickType|3815533801|wagerAmounts|replace", #deep link
"outcome_name": "Moneyline",
"outcome_line": null,
"outcome_over_under": null,
"outcome_target": "Los Angeles Angels"
},
... #all other lines offered
}
}
}
{
"timestamp": "2025-07-23T19:46:10.023175+00:00",
"action": "game_update",
"data": {
"sport": "MLB",
"sportsbook": "ballybet",
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"home_team": "New York Mets",
"away_team": "Los Angeles Angels",
"info": {
"id": 1022036664,
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"when": "2025-07-23, 01:09 PM",
"link": "https://play.ballybet.ca/sports#event/1022036664"
},
"outcomes": {
"New York Mets Moneyline": {
"odds": "-3333",
"link": "https://play.ballybet.ca/sports#event/1022036664?coupon=pickType|3815533797|wagerAmounts|replace", #deep link
"outcome_name": "Moneyline",
"outcome_line": null,
"outcome_over_under": null,
"outcome_target": "New York Mets"
},
"Los Angeles Angels Moneyline": {
"odds": "+900",
"link": "https://play.ballybet.ca/sports#event/1022036664?coupon=pickType|3815533801|wagerAmounts|replace", #deep link
"outcome_name": "Moneyline",
"outcome_line": null,
"outcome_over_under": null,
"outcome_target": "Los Angeles Angels"
},
... #all other lines offered
}
}
}
{
"timestamp": "2025-07-23T19:55:09.062375+00:00",
"action": "game_removed",
"data": {
"sport": "MLB",
"sportsbook": "ballybet",
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"home_team": "New York Mets",
"away_team": "Los Angeles Angels",
"info": {
"id": 1022036664,
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"when": "2025-07-23, 01:09 PM",
"link": "https://play.ballybet.ca/sports#event/1022036664"
},
"outcomes": {}
}
}
{
"timestamp": "2025-07-23T19:46:10.023175+00:00",
"action": "line_update",
"data": {
"sport": "MLB",
"sportsbook": "ballybet",
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"home_team": "New York Mets",
"away_team": "Los Angeles Angels",
"info": {
"id": 1022036664,
"game": "New York Mets vs Los Angeles Angels, 2025-07-23, 01",
"when": "2025-07-23, 01:09 PM",
"link": "https://play.ballybet.ca/sports#event/1022036664"
},
"outcomes": {
"New York Mets Moneyline": {
"odds": "-1250", #if line is suspended, closed, unavailable, this will be None or ''
"link": "https://play.ballybet.ca/sports#event/1022036664?coupon=pickType|3815533797|wagerAmounts|replace", #deep link
"outcome_name": "Moneyline",
"outcome_line": null,
"outcome_over_under": null,
"outcome_target": "New York Mets"
}
}
}
}
{
"timestamp": "2025-07-23T19:58:43.086382+00:00",
"action": "book_clear",
"data": {
"sport": {},
"sportsbook": "ballybet",
"game": {},
"home_team": {},
"away_team": {},
"info": {},
"outcomes": {}
}
}
{"action": "ping"}
Basic Example
Here's a complete basic example of connecting to and using BoltOdds:
import asyncio
import websockets
import json
async def run_client():
uri = "wss://spro.agency/api?key=YOUR_TOKEN"
while True:
try:
async with websockets.connect(uri) as websocket:
ack_message = await websocket.recv()
print(ack_message)
# Send the subscription message
subscribe_message = {
"action": "subscribe",
"filters": {
"sports": ["NBA", "MLB", "Wimbledon (M)"],
"sportsbooks": ["draftkings", "betmgm"],
"games":["San Francisco Giants vs Philadelphia Phillies, 2025-07-07, 09", "Corinthians vs Bragantino, 2025-07-13, 06"],
"markets":["Moneyline", "Spread"]
}
}
await websocket.send(json.dumps(subscribe_message))
# Listen for incoming messages
while True:
message = await websocket.recv()
data = json.loads(message)
if data['action'] == 'ping':
continue
#sent upon connection, initial state of odds subbed to
if data['action'] == 'initial_state':
...
#entire game odds update
elif data['action'] == 'game_update':
...
#games done
elif data['action'] == 'game_removed':
...
#game added
elif data['action'] == 'game_added':
...
#singular line odd update
#if odds r None or '', no odds available for line i.e its deleted, suspended etc
elif data['action'] == 'line_update':
...
#all games for this book have been cleared
elif data['action'] == 'book_clear':
...
except websockets.ConnectionClosed as e:
print("Connection closed — reason:", e)
print('Reconnecting...')
await asyncio.sleep(5)
continue
if __name__ == "__main__":
asyncio.run(run_client())
Troubleshooting
Common issues and their solutions:
Connection Fails
- Verify your API key is correct
- Check that you're using the correct WebSocket URL
- Ensure your firewall allows WebSocket connections
- Ensure you're sending subscription message soon after connecting
Authentication Errors
- Double-check your API key format
Support
Need help? We're here for you:
- Email: support@boltodds.com
- Documentation: Available 24/7 online