Trying to get UK bookmaker odds programmatically often means wrestling with web scraping. You build a scraper, it works for a week, then a bookmaker changes their site layout. Suddenly, your data pipeline is broken. This tutorial shows you a more robust way to integrate pre-match football odds JSON into your applications using a dedicated odds API.
Direct API access provides structured, reliable data without the constant maintenance overhead of scraping. You get consistent field names and stable endpoints, letting you focus on building your application. We'll walk through how to connect to a UK bookmaker odds API, fetch upcoming fixtures, and retrieve detailed pre-match football odds. This approach is ideal for building odds comparison sites, betting bots, or data analysis tools that need reliable data without scraping.
Prerequisites
Before you start fetching pre-match football odds programmatically, ensure you have a few things set up. These are standard for any API integration.
- API Key: You'll need an API key from ukoddsapi.com. You can get a free key by signing up on the website. This key authenticates your requests.
- Programming Language: This tutorial uses Python and Node.js (JavaScript). Choose the one you're most comfortable with.
- HTTP Client Library: For Python, we'll use
requests. For Node.js, the nativefetchAPI is sufficient. - Environment Setup: A basic development environment for your chosen language. For Python, ensure
pipis installed. For Node.js, ensurenpmis available. - Basic API Knowledge: Familiarity with REST APIs, JSON data, and HTTP requests.

Step 1: Authenticate and List Bookmakers
The first step in any API integration is authentication. For ukoddsapi.com, you send your API key in the X-Api-Key header with every request. It's good practice to store your API key as an environment variable, not directly in your code.
Once authenticated, you can query the API to see which UK bookmakers are supported. This helps you understand the coverage available for your application. The /v1/bookmakers endpoint provides a list of all available bookmakers, each with a unique bookmaker_code.
Python Example: Listing Bookmakers
import os
import requests
# Load your API key from an environment variable
API_KEY = os.environ.get("UKODDSAPI_KEY", "YOUR_API_KEY") # Replace YOUR_API_KEY if not using env var
BASE_URL = "https://api.ukoddsapi.com"
headers = {"X-Api-Key": API_KEY}
try:
response = requests.get(f"{BASE_URL}/v1/bookmakers", headers=headers, timeout=10)
response.raise_for_status() # Raise an exception for HTTP errors
bookmakers_data = response.json()
print("Supported UK Bookmakers:")
for bm in bookmakers_data.get("bookmakers", []):
print(f"- {bm['name']} (Code: {bm['bookmaker_code']})")
except requests.exceptions.RequestException as e:
print(f"Error fetching bookmakers: {e}")
This Python snippet fetches the list of bookmakers. It uses os.environ.get to safely retrieve your API key. The requests.get call includes the X-Api-Key header. We then iterate through the JSON response to print each bookmaker's name and code. This gives you a clear overview of the data sources.
Node.js Example: Listing Bookmakers
import fetch from 'node-fetch'; // For older Node.js versions, or if not using native fetch
import 'dotenv/config'; // For loading .env file variables
const API_KEY = process.env.UKODDSAPI_KEY || "YOUR_API_KEY"; // Replace YOUR_API_KEY if not using env var
const BASE_URL = "https://api.ukoddsapi.com";
async function listBookmakers() {
try {
const response = await fetch(`${BASE_URL}/v1/bookmakers`, {
headers: { "X-Api-Key": API_KEY }
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const bookmakersData = await response.json();
console.log("Supported UK Bookmakers:");
bookmakersData.bookmakers.forEach(bm => {
console.log(`- ${bm.name} (Code: ${bm.bookmaker_code})`);
});
} catch (error) {
console.error(`Error fetching bookmakers: ${error.message}`);
}
}
listBookmakers();
The Node.js example performs the same task using fetch. It's an asynchronous function, so we use await to handle the promise. Error handling checks the response.ok status. Both examples demonstrate how to correctly authenticate and retrieve initial data from the UK bookmaker odds API.
Step 2: Fetch Upcoming Football Events
With authentication handled, the next logical step is to discover upcoming football fixtures. You need to know which matches are scheduled before you can request their specific odds. The /v1/football/events endpoint allows you to query for events by date. You can also filter for events that already have odds available. This is crucial for building any application that needs pre-match football odds JSON.
Python Example: Fetching Events
import os
import requests
from datetime import date, timedelta
API_KEY = os.environ.get("UKODDSAPI_KEY", "YOUR_API_KEY")
BASE_URL = "https://api.ukoddsapi.com"
headers = {"X-Api-Key": API_KEY}
# Get events for tomorrow
tomorrow = date.today() + timedelta(days=1)
schedule_date = tomorrow.strftime("%Y-%m-%d")
try:
events_response = requests.get(
f"{BASE_URL}/v1/football/events",
headers=headers,
params={"schedule_date": schedule_date, "has_odds": "true", "per_page": "5"},
timeout=30,
)
events_response.raise_for_status()
events_data = events_response.json()
print(f"\nUpcoming Football Events with Odds for {schedule_date}:")
if events_data.get("events"):
for event in events_data["events"]:
print(f" Event ID: {event['event_id']}")
print(f" League: {event['league_name']}")
print(f" Match: {event['home_team']} vs {event['away_team']}")
print(f" Kickoff: {event['kickoff_utc']}")
print(f" Markets with Odds: {', '.join(event['markets_with_odds'])}")
print("-" * 30)
# Store the first event_id for the next step
first_event_id = events_data["events"][0]["event_id"]
print(f"First event ID for detailed odds: {first_event_id}")
else:
print("No events found with odds for this date.")
except requests.exceptions.RequestException as e:
print(f"Error fetching events: {e}")
This Python code retrieves a summary of upcoming football events. It specifically asks for events scheduled for tomorrow that has_odds=true. The per_page parameter limits the results, which is useful for pagination in larger applications. The output includes key details like event_id, league_name, teams, and kickoff time. The event_id is crucial for fetching detailed odds in the next step.
Node.js Example: Fetching Events
import fetch from 'node-fetch';
import 'dotenv/config';
import { format, addDays } from 'date-fns'; // Using date-fns for date manipulation
const API_KEY = process.env.UKODDSAPI_KEY || "YOUR_API_KEY";
const BASE_URL = "https://api.ukoddsapi.com";
async function fetchFootballEvents() {
try {
const tomorrow = addDays(new Date(), 1);
const scheduleDate = format(tomorrow, 'yyyy-MM-dd');
const params = new URLSearchParams({
schedule_date: scheduleDate,
has_odds: 'true',
per_page: '5'
});
const response = await fetch(`${BASE_URL}/v1/football/events?${params.toString()}`, {
headers: { "X-Api-Key": API_KEY }
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const eventsData = await response.json();
console.log(`\nUpcoming Football Events with Odds for ${scheduleDate}:`);
let firstEventId = null;
if (eventsData.events && eventsData.events.length > 0) {
eventsData.events.forEach(event => {
console.log(` Event ID: ${event.event_id}`);
console.log(` League: ${event.league_name}`);
console.log(` Match: ${event.home_team} vs ${event.away_team}`);
console.log(` Kickoff: ${event.kickoff_utc}`);
console.log(` Markets with Odds: ${event.markets_with_odds.join(', ')}`);
console.log("-".repeat(30));
if (!firstEventId) {
firstEventId = event.event_id;
}
});
console.log(`First event ID for detailed odds: ${firstEventId}`);
} else {
console.log("No events found with odds for this date.");
}
return firstEventId; // Return the first event ID for the next step
} catch (error) {
console.error(`Error fetching events: ${error.message}`);
return null;
}
}
// Example usage:
// const eventId = await fetchFootballEvents();
// if (eventId) { /* proceed to fetch odds */ }
The Node.js version uses date-fns for easy date formatting, though native Date objects could also work. It constructs query parameters using URLSearchParams for clarity. The logic is similar: fetch events, filter for those with odds, and extract the event_id for further use. This demonstrates how to get UK bookmaker odds programmatically by first identifying the relevant fixtures.
Step 3: Retrieve Detailed Pre-Match Odds
Once you have an event_id, you can fetch the detailed pre-match odds for that specific fixture. This is where you get the actual pricing data from various bookmakers. The /v1/football/events/{event_id}/odds endpoint provides a comprehensive JSON response, including markets and selections. You can specify the package (e.g., core for basic markets) and odds_format (e.g., decimal). This is the core of getting pre-match football odds JSON.
Python Example: Fetching Detailed Odds
import os
import requests
from datetime import date, timedelta
API_KEY = os.environ.get("UKODDSAPI_KEY", "YOUR_API_KEY")
BASE_URL = "https://api.ukoddsapi.com"
headers = {"X-Api-Key": API_KEY}
# --- Re-run event fetching to get an event_id ---
tomorrow = date.today() + timedelta(days=1)
schedule_date = tomorrow.strftime("%Y-%m-%d")
first_event_id = None
try:
events_response = requests.get(
f"{BASE_URL}/v1/football/events",
headers=headers,
params={"schedule_date": schedule_date, "has_odds": "true", "per_page": "1"},
timeout=30,
)
events_response.raise_for_status()
events_data = events_response.json()
if events_data.get("events"):
first_event_id = events_data["events"][0]["event_id"]
else:
print("No events found with odds for this date to fetch detailed odds.")
exit()
except requests.exceptions.RequestException as e:
print(f"Error fetching event for detailed odds: {e}")
exit()
# --- End re-run event fetching ---
if first_event_id:
print(f"\nFetching detailed odds for Event ID: {first_event_id}")
try:
odds_response = requests.get(
f"{BASE_URL}/v1/football/events/{first_event_id}/odds",
headers=headers,
params={"package": "core", "odds_format": "decimal"},
timeout=60,
)
odds_response.raise_for_status()
odds_data = odds_response.json()
print(f"Event Title: {odds_data.get('event_title')}")
print(f"Kickoff: {odds_data.get('kickoff_utc')}")
# Iterate through markets and selections
for market in odds_data.get("markets", []):
print(f"\nMarket: {market['market_name']} (Group: {market['market_group']})")
for selection in market.get("selections", []):
print(f" Selection: {selection['selection_name']}")
for bookmaker_odds in selection.get("odds", []):
bookmaker_name = next(
(bm['name'] for bm in bookmakers_data['bookmakers'] if bm['bookmaker_code'] == bookmaker_odds['bookmaker_code']),
bookmaker_odds['bookmaker_code']
)
print(f" - {bookmaker_name}: {bookmaker_odds['price']} (Status: {bookmaker_odds['status']})")
except requests.exceptions.RequestException as e:
print(f"Error fetching detailed odds: {e}")
This Python code snippet fetches the full pre-match odds for a single event. It first ensures an event_id is available (by re-running the event fetch for simplicity). Then, it calls the /odds endpoint, specifying core package and decimal odds format. The response is parsed to show the event title, kickoff, and then iterates through each market and its selections, displaying odds from various bookmakers. The bookmakers_data from Step 1 is used here to map bookmaker_code back to a human-readable name.
Here's a truncated example of the JSON response you might receive:
{
"schema_version": "1.0",
"event_id": "EVT12345",
"event_title": "Manchester United vs Liverpool",
"kickoff_utc": "2026-04-26T15:00:00Z",
"summary": {
"league_name": "Premier League",
"home_team": "Manchester United",
"away_team": "Liverpool"
},
"markets": [
{
"market_id": "MKT001",
"market_name": "Match Winner",
"market_group": "main",
"selection_count": 3,
"selections": [
{
"selection_name": "Manchester United",
"line": null,
"odds": [
{ "bookmaker_code": "UO001", "price": 2.50, "status": "active" },
{ "bookmaker_code": "UO002", "price": 2.60, "status": "active" }
]
},
{
"selection_name": "Draw",
"line": null,
"odds": [
{ "bookmaker_code": "UO001", "price": 3.40, "status": "active" },
{ "bookmaker_code": "UO002", "price": 3.30, "status": "active" }
]
},
{
"selection_name": "Liverpool",
"line": null,
"odds": [
{ "bookmaker_code": "UO001", "price": 2.80, "status": "active" },
{ "bookmaker_code": "UO002", "price": 2.75, "status": "active" }
]
}
]
}
],
"note": "Response truncated for brevity."
}
This JSON structure provides a clear, normalized view of the odds. Each market contains selections, and each selection lists odds from different bookmaker_codes. The price field gives the decimal odds. This is the raw data you need to integrate UK bookmaker odds programmatically.
Node.js Example: Fetching Detailed Odds
import fetch from 'node-fetch';
import 'dotenv/config';
import { format, addDays } from 'date-fns';
const API_KEY = process.env.UKODDSAPI_KEY || "YOUR_API_KEY";
const BASE_URL = "https://api.ukoddsapi.com";
async function fetchDetailedOdds() {
let firstEventId = null;
let bookmakersData = { bookmakers: [] }; // Initialize bookmakersData
try {
// --- Re-run bookmaker fetching ---
const bmResponse = await fetch(`${BASE_URL}/v1/bookmakers`, {
headers: { "X-Api-Key": API_KEY }
});
if (!bmResponse.ok) throw new Error(`HTTP error! Status: ${bmResponse.status} for bookmakers`);
bookmakersData = await bmResponse.json();
// --- End re-run bookmaker fetching ---
// --- Re-run event fetching ---
const tomorrow = addDays(new Date(), 1);
const scheduleDate = format(tomorrow, 'yyyy-MM-dd');
const eventParams = new URLSearchParams({
schedule_date: scheduleDate,
has_odds: 'true',
per_page: '1'
});
const eventResponse = await fetch(`${BASE_URL}/v1/football/events?${eventParams.toString()}`, {
headers: { "X-Api-Key": API_KEY }
});
if (!eventResponse.ok) throw new Error(`HTTP error! Status: ${eventResponse.status} for events`);
const eventsData = await eventResponse.json();
if (eventsData.events && eventsData.events.length > 0) {
firstEventId = eventsData.events[0].event_id;
} else {
console.log("No events found with odds for this date to fetch detailed odds.");
return;
}
// --- End re-run event fetching ---
if (firstEventId) {
console.log(`\nFetching detailed odds for Event ID: ${firstEventId}`);
const oddsParams = new URLSearchParams({
package: 'core',
odds_format: 'decimal'
});
const oddsResponse = await fetch(`${BASE_URL}/v1/football/events/${firstEventId}/odds?${oddsParams.toString()}`, {
headers: { "X-Api-Key": API_KEY }
});
if (!oddsResponse.ok) {
throw new Error(`HTTP error! Status: ${oddsResponse.status}`);
}
const oddsData = await oddsResponse.json();
console.log(`Event Title: ${oddsData.event_title}`);
console.log(`Kickoff: ${oddsData.kickoff_utc}`);
for (const market of oddsData.markets || []) {
console.log(`\nMarket: ${market.market_name} (Group: ${market.market_group})`);
for (const selection of market.selections || []) {
console.log(` Selection: ${selection.selection_name}`);
for (const bookmakerOdds of selection.odds || []) {
const bookmakerName = bookmakersData.bookmakers.find(bm => bm.bookmaker_code === bookmakerOdds.bookmaker_code)?.name || bookmakerOdds.bookmaker_code;
console.log(` - ${bookmakerName}: ${bookmakerOdds.price} (Status: ${bookmakerOdds.status})`);
}
}
}
}
} catch (error) {
console.error(`Error fetching detailed odds: ${error.message}`);
}
}
fetchDetailedOdds();
The Node.js example similarly fetches bookmakers and events first to ensure it has a valid event_id. It then makes the request to the /odds endpoint. The code iterates through the markets and selections arrays, printing the odds for each selection from various bookmakers. This comprehensive output shows how to integrate UK bookmaker odds programmatically and process the detailed pre-match football odds JSON.
Common Mistakes When Fetching Odds
Integrating with any API can have its quirks. Here are some common pitfalls developers encounter when trying to get UK bookmaker odds programmatically, along with how to avoid them.
- Ignoring Rate Limits: Hitting endpoints too frequently will lead to 429 Too Many Requests errors. Implement exponential backoff and respect the
Retry-Afterheader. - Hardcoding API Keys: Storing your API key directly in your source code is a security risk. Always use environment variables or a secure configuration management system.
- Not Handling Errors: Network issues, invalid parameters, or API downtime can occur. Always wrap API calls in
try-except(Python) ortry-catch(Node.js) blocks and check HTTP status codes. - Misunderstanding "Live" vs. "Pre-match": UK Odds API provides pre-match odds for scheduled fixtures before kickoff. It does not provide in-play or real-time trading data. If you need updated pre-match prices, poll the API at sensible intervals.
- Inefficient Data Fetching: Don't fetch all odds for all events if you only need a few. Use parameters like
schedule_date,has_odds, andper_pageto narrow down your requests. - Parsing Incorrect Fields: Always refer to the API documentation or example responses to ensure you are accessing the correct JSON field names and data types. Minor typos can cause your application to break.
- Not Caching Data: For data that doesn't change frequently (like bookmaker lists or event metadata), cache it locally to reduce API calls and improve performance. Odds change, but not every second.

Options and Alternatives for Odds Data
When you need to get UK bookmaker odds programmatically, you have a few options beyond direct API integration. Each comes with its own set of trade-offs. Understanding these can help you choose the right approach for your project.
| Method | Pros | Cons | Best For |
|---|---|---|---|
| Managed Odds API | Reliable, structured JSON, stable endpoints, fast | Cost, dependency on provider, specific coverage | Building robust applications, high-volume data needs, no scraping overhead |
| Web Scraping | Free (initially), full control over data | High maintenance, IP blocking, legal/ethical concerns, slow, brittle | Small, personal projects, highly niche data not available elsewhere |
| Bookmaker Official APIs | Direct from source, often free | Limited coverage, inconsistent APIs, rate limits, often in-play focused | Specific bookmaker integrations, direct trading bots |
| Data Feeds (Raw) | Comprehensive, high-frequency | Very expensive, complex integration, often requires dedicated infrastructure | Enterprise-level data analysis, trading desks, large-scale platforms |
Managed odds APIs, like ukoddsapi.com, offer a balance of reliability, ease of use, and comprehensive coverage for specific markets (in our case, UK pre-match football). They abstract away the complexities of dealing with individual bookmakers, providing a normalized data stream. Scraping, while seemingly free, quickly becomes a significant time sink for any serious project due to constant breakages and IP management.
FAQ
Here are some common questions developers ask when integrating with an odds API.
How often should I poll the API for updated odds?
For pre-match football odds, polling every few minutes (e.g., 1-5 minutes) is generally sufficient. Odds don't typically change second-by-second before kickoff unless there's significant market movement or team news. Check your API plan's rate limits and adjust accordingly.
Can I get historical odds data through the API?
Yes, ukoddsapi.com offers historical odds data on its Pro and Business plans. This allows you to retrieve past pre-match odds for backtesting models or analyzing market trends. The GET /v1/football/events/{event_id}/odds endpoint can be used with a specific event_id from the past.
What if a specific bookmaker isn't listed in the API response?
If a bookmaker you expect isn't in the /v1/bookmakers response, it means they are not currently supported by the API. Coverage can vary by plan tier; higher tiers often include more bookmakers. You can check the ukoddsapi.com website for the latest list of supported bookmakers.
How do I handle pagination when fetching many events?
The /v1/football/events endpoint supports per_page and page parameters. When fetching events, you can specify per_page to get a certain number of results per request and then increment the page parameter in subsequent requests until no more events are returned. This allows you to efficiently retrieve large datasets.
What does "pre-match" mean in the context of this API?
"Pre-match" means the odds are for fixtures scheduled to occur in the future, before the event has started. These are the opening and closing odds offered by bookmakers prior to kickoff. This API does not provide "in-play" or "live" odds that update during a match.
Conclusion
Getting UK bookmaker odds programmatically doesn't have to be a constant battle against web scraping. By leveraging a dedicated odds API, you gain access to structured, reliable pre-match football odds JSON. This tutorial walked you through the process, from authentication and event discovery to fetching detailed odds using Python and Node.js.
This approach saves you development time and maintenance headaches, letting you focus on building innovative applications. For robust and consistent pre-match football odds data, explore the capabilities of UK Odds API.