guide

Building a Real-Time Arbitrage System with a UK Odds API

Finding profitable arbitrage opportunities in sports betting means spotting discrepancies across bookmakers fast. Manually checking dozens of sites is a non-starter. Building a real-time arbitrage system automates this, giving you a significant edge by programmatically identifying surebets before they disappear.

This guide walks through the technical steps of building a real-time arbitrage system using a dedicated UK bookmaker odds API. We will focus on pre-match football odds JSON data, which is stable enough for reliable arbitrage detection. The goal is to show you how to set up a robust system for arbitrage betting API integration, avoiding the pitfalls of web scraping.

Prerequisites

Before diving into the code, ensure you have the following:

  • UK Odds API Key: You will need an API key from ukoddsapi.com. For direct access to the arbitrage endpoint, a Business tier subscription is required. For manual calculation, a Pro tier offers comprehensive market coverage across 27 UK bookmakers.
  • Python 3.x: Our code examples will use Python.
  • requests library: Install it via pip install requests.
  • Basic understanding of REST APIs and JSON: We will be interacting with a RESTful API and parsing JSON responses.
  • A database (optional but recommended): For storing and tracking events, odds, and detected arbitrage opportunities.

Step 1: Fetching Upcoming Football Events

The first step in building a real-time arbitrage system is to get a list of upcoming football fixtures. We need events that have associated pre-match odds available from various bookmakers. The /v1/football/events endpoint provides this, allowing you to filter by date and specify that you only want events with odds.

Here is how to fetch the next few football events with available odds using Python:

import os
import requests
from datetime import date, timedelta

API_KEY = os.environ.get("UKODDSAPI_KEY", "YOUR_API_KEY") # Replace with your actual API key or set as env var
BASE_URL = "https://api.ukoddsapi.com"
headers = {"X-Api-Key": API_KEY}

today = date.today()
tomorrow = today + timedelta(days=1)

try:
    events_response = requests.get(
        f"{BASE_URL}/v1/football/events",
        headers=headers,
        params={"schedule_date": tomorrow.isoformat(), "has_odds": "true", "per_page": "10"},
        timeout=30,
    )
    events_response.raise_for_status() # Raise an exception for HTTP errors
    events_data = events_response.json()

    print(f"Fetched {events_data.get('count', 0)} events for {tomorrow.isoformat()}:")
    for event in events_data.get("events", [])[:3]: # Print first 3 for brevity
        print(f"  ID: {event['event_id']}, Match: {event['home_team']} vs {event['away_team']}, Kickoff: {event['kickoff_utc']}")

except requests.exceptions.RequestException as e:
    print(f"Error fetching events: {e}")

code snippet showing API request and JSON response for football events, with data flowing

This Python script queries the /v1/football/events endpoint for matches scheduled for tomorrow that have odds. It then prints the event_id, team names, and kickoff time for the first few results. The event_id is crucial for retrieving detailed odds in the next step.

A typical response for the events endpoint looks like this:

{
  "schema_version": "1.0",
  "count": 10,
  "events": [
    {
      "event_id": "EVT00123456789",
      "league_name": "Premier League",
      "home_team": "Manchester United",
      "away_team": "Liverpool",
      "kickoff_utc": "2026-04-30T15:00:00Z",
      "markets_with_odds": ["match_betting", "over_under_2_5_goals"],
      "unique_bookmaker_codes": ["UO001", "UO003", "UO005"]
    },
    {
      "event_id": "EVT00123456790",
      "league_name": "Championship",
      "home_team": "Leeds United",
      "away_team": "Leicester City",
      "kickoff_utc": "2026-04-30T19:45:00Z",
      "markets_with_odds": ["match_betting"],
      "unique_bookmaker_codes": ["UO001", "UO002", "UO004"]
    }
  ],
  "note": "Response truncated for example."
}

The events array contains objects, each representing a football fixture. We use event_id to fetch specific odds later. The unique_bookmaker_codes field gives a quick overview of which bookmakers have odds for this event.

Step 2: Retrieving Pre-Match Odds for an Event

Once you have an event_id, you can fetch the detailed pre-match football odds JSON for that specific fixture. The /v1/football/events/{event_id}/odds endpoint provides all available markets and their selections across supported bookmakers. This is the core data needed for building a real-time arbitrage system.

Here is how to retrieve odds for a single event:

import os
import requests

API_KEY = os.environ.get("UKODDSAPI_KEY", "YOUR_API_KEY")
BASE_URL = "https://api.ukoddsapi.com"
headers = {"X-Api-Key": API_KEY}

# Using a placeholder event_id for demonstration. In a real system, this would come from Step 1.
example_event_id = "EVT00123456789"

try:
    odds_response = requests.get(
        f"{BASE_URL}/v1/football/events/{example_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"Odds for {odds_data.get('event_title')}:")
    for market in odds_data.get("markets", [])[:1]: # Print first market for brevity
        print(f"  Market: {market['market_name']}")
        for selection in market.get("selections", [])[:3]: # Print first 3 selections
            print(f"    Selection: {selection['selection_name']}")
            for bookmaker_odds in selection.get("odds", [])[:2]: # Print first 2 bookmaker odds
                print(f"      Bookmaker: {bookmaker_odds['bookmaker_code']}, Odds: {bookmaker_odds['price']}")

except requests.exceptions.RequestException as e:
    print(f"Error fetching odds: {e}")

This code snippet fetches the odds for a given event_id using the core package and decimal format. The response contains a markets array, where each market has selections, and each selection lists odds from various bookmakers.

A simplified JSON response for odds looks like this:

{
  "event_id": "EVT00123456789",
  "event_title": "Manchester United vs Liverpool",
  "kickoff_utc": "2026-04-30T15:00:00Z",
  "markets": [
    {
      "market_id": "MKT001",
      "market_name": "Match Betting",
      "market_group": "main",
      "selections": [
        {
          "selection_name": "Manchester United",
          "odds": [
            { "bookmaker_code": "UO001", "price": 2.50, "status": "active" },
            { "bookmaker_code": "UO002", "price": 2.40, "status": "active" }
          ]
        },
        {
          "selection_name": "Draw",
          "odds": [
            { "bookmaker_code": "UO001", "price": 3.20, "status": "active" },
            { "bookmaker_code": "UO002", "price": 3.30, "status": "active" }
          ]
        },
        {
          "selection_name": "Liverpool",
          "odds": [
            { "bookmaker_code": "UO001", "price": 2.80, "status": "active" },
            { "bookmaker_code": "UO002", "price": 2.90, "status": "active" }
          ]
        }
      ]
    }
  ],
  "note": "Response truncated for example."
}

This structure provides all the necessary data points: bookmaker_code, selection_name, and price for each outcome within a market.

Step 3: Identifying Arbitrage Opportunities

With the odds data in hand, the next step is to actually find arbitrage opportunities. This is the core of building a real-time arbitrage system explained.

There are two main approaches:

  1. Using the dedicated Arbitrage API endpoint: For Business tier users, ukoddsapi.com offers a direct /v1/football/arbitrage endpoint. This endpoint is designed to return pre-calculated arbitrage opportunities, simplifying the detection process significantly.
  2. Manual calculation from raw odds: For Pro tier users or those wanting to understand the underlying mechanics, you can calculate arbitrage manually from the detailed odds fetched in Step 2.

Option A: Using the Dedicated Arbitrage API (Business Tier)

If you are on the Business tier, you can use the /v1/football/arbitrage endpoint. This endpoint does the heavy lifting for you, returning identified arbitrage bets.

import os
import requests
from datetime import date

API_KEY = os.environ.get("UKODDSAPI_KEY", "YOUR_API_KEY")
BASE_URL = "https://api.ukoddsapi.com"
headers = {"X-Api-Key": API_KEY}

today = date.today()

try:
    arbitrage_response = requests.get(
        f"{BASE_URL}/v1/football/arbitrage",
        headers=headers,
        params={"date": today.isoformat(), "min_profit": "0.01", "round_to": "2"},
        timeout=60,
    )
    arbitrage_response.raise_for_status()
    arbitrage_data = arbitrage_response.json()

    if arbitrage_data.get("arbitrage_opportunities"):
        print(f"Found {len(arbitrage_data['arbitrage_opportunities'])} arbitrage opportunities for {today.isoformat()}:")
        for arb in arbitrage_data["arbitrage_opportunities"][:2]: # Print first 2 for brevity
            print(f"  Event: {arb['event_title']}, Profit: {arb['profit_percentage']:.2f}%")
            for leg in arb['legs']:
                print(f"    Bet: {leg['selection_name']} @ {leg['bookmaker_code']} ({leg['price']})")
    else:
        print(f"No arbitrage opportunities found for {today.isoformat()}.")

except requests.exceptions.RequestException as e:
    print(f"Error fetching arbitrage data: {e}")

abstract representation of arbitrage calculation, with multiple odds converging to a single profitable outcome

This endpoint is the most efficient way for building a real-time arbitrage system integration. It handles the complex logic of comparing odds across all bookmakers for all markets and returns only the profitable opportunities.

Option B: Manual Arbitrage Calculation (Pro Tier)

For those on the Pro tier or simply interested in the underlying algorithm, you can implement the arbitrage detection logic yourself. An arbitrage opportunity exists when the sum of the inverse of the best odds for each outcome in a market is less than 1.

The formula for a two-way market (e.g., Over/Under 2.5 Goals) is:

1 / Odd_1 + 1 / Odd_2 < 1

For a three-way market (e.g., Match Betting: Home, Draw, Away):

1 / Odd_Home + 1 / Odd_Draw + 1 / Odd_Away < 1

The profit percentage is then (1 / Sum_of_Inverse_Odds - 1) * 100.

Here is a simplified Python function to detect arbitrage for a 3-way market, assuming you have the best odds for each selection:

def find_arbitrage_3_way(odds_home, odds_draw, odds_away):
    """
    Detects arbitrage for a 3-way market (e.g., Match Betting).
    Assumes decimal odds.
    """
    if not all([odds_home, odds_draw, odds_away]):
        return None # Missing odds

    implied_probability_sum = (1 / odds_home) + (1 / odds_draw) + (1 / odds_away)

    if implied_probability_sum < 1:
        profit_percentage = (1 / implied_probability_sum - 1) * 100
        return {
            "profit_percentage": profit_percentage,
            "implied_probability_sum": implied_probability_sum
        }
    return None

# Example usage (you'd get these best odds from the API response)
best_odds_home = 2.50 # From Bookmaker A
best_odds_draw = 3.30 # From Bookmaker B
best_odds_away = 3.00 # From Bookmaker C

arb_opportunity = find_arbitrage_3_way(best_odds_home, best_odds_draw, best_odds_away)

if arb_opportunity:
    print(f"Arbitrage found! Profit: {arb_opportunity['profit_percentage']:.2f}%")
else:
    print("No arbitrage found for these odds.")

To implement this fully, you would iterate through the markets in the odds data (from Step 2). For each market (e.g., "Match Betting"), you would:

  1. Identify all unique selections (e.g., "Home", "Draw", "Away").
  2. For each selection, find the highest available odd across all bookmakers. The /v1/football/events/{event_id}/odds/best endpoint can simplify this by giving you the best price per selection directly.
  3. Apply the arbitrage formula using these best odds.

This manual approach provides a deeper understanding of building a real-time arbitrage system explained and offers flexibility if you want to apply custom filters or logic.

Step 4: Automating the Detection Process

A truly "real-time" arbitrage system requires automation. This means continuously polling for updated odds, processing them, and notifying you of new opportunities. This is where the "real-time" aspect of building a real-time arbitrage system comes into play.

Here's a high-level overview of an automation loop:

  1. Schedule Event Fetching: Periodically fetch upcoming events (e.g., once an hour) to ensure your system knows about all new fixtures.
  2. Poll Odds Data: For each active event, poll the /v1/football/events/{event_id}/odds (or /v1/football/arbitrage) endpoint at regular intervals. The frequency depends on your API plan's rate limits. For example, a Pro plan offers 5,000 requests/hour, allowing for frequent updates across many events.
  3. Process and Detect: If using the dedicated arbitrage endpoint, simply parse the response. If calculating manually, parse the raw odds, find the best prices for each selection, and run your arbitrage detection logic.
  4. Store Data: Save event details, raw odds, and detected arbitrage opportunities to a database. This helps track changes, history, and manage notifications.
  5. Notification System: When a new arbitrage opportunity is detected (or an existing one changes significantly), send an alert. Options include: Email Telegram/Discord bot messages
    • Push notifications to a custom app
  6. Error Handling and Logging: Implement robust error handling for API requests, network issues, and data parsing. Log all activities and errors for debugging and monitoring.

Remember to respect API rate limits. Polling too aggressively will lead to temporary blocks. Design your system to back off gracefully and retry requests.

Common Mistakes in Building a Real-Time Arbitrage System

Building a real-time arbitrage system comes with its own set of challenges. Avoiding these common mistakes will save you time and frustration:

  • Ignoring API Rate Limits: Aggressive polling without respecting X-RateLimit-Remaining headers will get your IP blocked. Implement exponential backoff and adhere to your plan's limits.
  • Not Normalising Data: Bookmakers might use different names for the same market ("Match Odds" vs "1X2") or selections ("Man Utd" vs "Manchester United"). Normalise these to ensure accurate comparisons. UK Odds API helps with this by providing standardised market_name and selection_name fields.
  • Relying on Stale Data: Odds change constantly. An arbitrage opportunity can vanish in seconds. Your system needs to fetch and process data as close to "real-time" as your API plan allows.
  • Miscalculating Arbitrage: Small rounding errors or incorrect formulas can lead to "false positives" where you think there's a profit, but there isn't. Double-check your math.
  • Overlooking Bookmaker Commissions/Fees: Some bookmakers (especially exchanges) charge commission on winnings. Factor this into your profit calculations.
  • Not Handling Suspended Markets: Bookmakers frequently suspend markets or change odds rapidly. Your system must detect and ignore suspended selections ("status": "suspended") to prevent placing invalid bets.
  • Lack of Robust Error Handling: Network issues, API errors, or unexpected JSON structures can break your system. Implement try-except blocks and logging to handle these gracefully.

Options and Alternatives for Odds Data

When considering building a real-time arbitrage system, developers often weigh different approaches for sourcing odds data. Here's a comparison:

Data Source UK Bookmaker Coverage Ease of Integration Reliability & Speed Cost
UK Odds API Excellent (27+ UK bookmakers on Pro/Business tiers) High High (normalised, dedicated arbitrage endpoint) Tiered pricing (Free, Starter, Pro, Business)
Web Scraping (DIY) Varies (depends on effort per site) Low Low (prone to breakage, IP bans, slow) High (development time, proxy costs, maintenance)
Other Generic Odds APIs Often limited for specific UK bookmakers Medium Medium (may lack pre-match focus, UK coverage) Varies widely, often less transparent for UK markets

The choice depends on your technical resources, budget, and the level of reliability you need. For serious arbitrage, an odds API without scraping is almost always the superior choice due to its stability and structured data.

FAQ

How often should I poll for odds updates when building an arbitrage system?

The polling frequency depends on your API plan's rate limits and how "real-time" you need your system to be. For ukoddsapi.com, paid plans offer requests per hour (e.g., 5,000 requests/hour on Pro), allowing for frequent updates across many events. You should poll as often as possible within your limits, typically every few seconds or minutes for active events.

What is the minimum profit margin for a viable arbitrage opportunity?

A viable profit margin for arbitrage is subjective but usually starts around 0.5% to 1%. This accounts for potential bookmaker commissions, minor odds fluctuations, and the time it takes to place bets. Smaller margins might not be worth the effort or risk.

How do I handle suspended markets or changed odds in my system?

Your system should continuously check the status field for each selection in the API response. If a selection's status is suspended or inactive, exclude it from your arbitrage calculations. If odds change, re-run your arbitrage detection immediately.

Is pre-match data sufficient for building a real-time arbitrage system?

Yes, pre-match data is often preferred for arbitrage. While in-play odds change faster, pre-match odds are generally more stable, giving you a wider window to place bets. The challenge is still to be fast enough to act on the pre-match opportunities before bookmakers adjust their lines.

What are the legal considerations for building such a system?

Building an arbitrage system is generally legal. However, bookmakers often have terms and conditions against "arbing" or using automated systems. While using an API is not illegal, bookmakers may limit or close accounts that consistently profit from arbitrage. Always be aware of the terms of service for each bookmaker you use.

Conclusion

Building a real-time arbitrage system is a complex but rewarding technical challenge. By leveraging a robust UK bookmaker odds API like ukoddsapi.com, you can overcome the significant hurdles of data collection and normalisation. Whether you use the dedicated arbitrage endpoint or implement your own logic from pre-match football odds JSON, an API provides the reliable, structured data you need to identify profitable opportunities efficiently and without the headache of constant web scraping.

Get started with your arbitrage system today by exploring the UK Odds API documentation and examples at ukoddsapi.com.