{"id":2509,"date":"2026-03-17T10:00:00","date_gmt":"2026-03-17T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=2509"},"modified":"2026-03-13T13:27:54","modified_gmt":"2026-03-13T13:27:54","slug":"arbitrage-betting-bot-python","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/","title":{"rendered":"How to Build an Arbitrage Betting Bot with Python (Free API)"},"content":{"rendered":"<h2>What Is Arbitrage Betting?<\/h2>\n<p>Arbitrage betting (&#8220;arbing&#8221;) is the practice of betting on <strong>every possible outcome<\/strong> of an event across different bookmakers, where the combined implied probability is less than 100%. The result: guaranteed profit regardless of who wins.<\/p>\n<p>Here is a quick example. A soccer match has three outcomes (Home, Draw, Away):<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Outcome<\/th>\n<th>Bookmaker<\/th>\n<th>Odds<\/th>\n<th>Implied Prob<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Home Win<\/td>\n<td>Pinnacle<\/td>\n<td>2.55<\/td>\n<td>39.2%<\/td>\n<\/tr>\n<tr>\n<td>Draw<\/td>\n<td>Bet365<\/td>\n<td>3.80<\/td>\n<td>26.3%<\/td>\n<\/tr>\n<tr>\n<td>Away Win<\/td>\n<td>1xBet<\/td>\n<td>3.20<\/td>\n<td>31.3%<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Total implied probability: <strong>96.8%<\/strong>. That is under 100%, which means you can stake proportionally on all three outcomes and lock in a 3.2% profit no matter what happens.<\/p>\n<p>The catch? To find arbs, you need odds from <strong>as many bookmakers as possible<\/strong>. The more books you cover, the more arbs you find. That is why most arb scanners fail &mdash; they only check 20&ndash;40 soft bookmakers.<\/p>\n<h2>Why Most Arbitrage Bots Fail<\/h2>\n<p>Before we build anything, let us talk about why most DIY arb bots produce zero results.<\/p>\n<h3>1. Not Enough Bookmakers<\/h3>\n<p>The Odds API covers roughly 40 soft bookmakers. Arbs between soft books are razor-thin and vanish in seconds. Real, actionable arbs live in the spread between <strong>sharp bookmakers<\/strong> (Pinnacle, Singbet, SBOBet) and softs (Bet365, DraftKings, FanDuel). If your API does not carry sharps, you are scanning a puddle instead of an ocean.<\/p>\n<h3>2. No Sharp Bookmakers<\/h3>\n<p>Pinnacle, Singbet, and SBOBet set the &#8220;true line.&#8221; When a soft bookmaker is slow to adjust, the gap between their price and the sharp line creates an arb. Most odds APIs do not carry these books at all. OddsPapi carries all three, plus 350+ total bookmakers including crypto and niche books like 1xBet and GG.BET.<\/p>\n<h3>3. Polling Latency<\/h3>\n<p>If you poll every 30 seconds, the arb is gone before your code even prints it. The best arbs last seconds, not minutes. This is where <a href=\"https:\/\/oddspapi.io\/blog\/websocket-odds-api-real-time-betting-data\">WebSocket streaming<\/a> changes the game &mdash; OddsPapi pushes odds changes to you in real-time instead of waiting for you to ask.<\/p>\n<h2>Building an Arb Bot: The Odds API vs OddsPapi<\/h2>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Feature<\/th>\n<th>The Odds API<\/th>\n<th>OddsPapi<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Bookmakers<\/td>\n<td>~40 (soft only)<\/td>\n<td>350+ (sharps + softs)<\/td>\n<\/tr>\n<tr>\n<td>Sharp Books (Pinnacle, Singbet)<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Crypto\/Niche Books<\/td>\n<td>No<\/td>\n<td>Yes (1xBet, GG.BET)<\/td>\n<\/tr>\n<tr>\n<td>Real-Time WebSocket<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Free Historical Data<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Free Tier<\/td>\n<td>500 req\/month<\/td>\n<td>250 req\/month<\/td>\n<\/tr>\n<tr>\n<td>Arb Detection Potential<\/td>\n<td>Low (limited coverage)<\/td>\n<td>High (sharp + soft spread)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The math is simple: more bookmakers = more price discrepancies = more arbs. With 350+ books including sharps, OddsPapi gives your scanner the coverage it needs to actually find opportunities.<\/p>\n<h2>Build an Arbitrage Scanner in Python<\/h2>\n<p>Let us build a working arb scanner from scratch. This code is tested against the live OddsPapi API and ready to run.<\/p>\n<h3>Step 1: Install Dependencies &amp; Set Up<\/h3>\n<pre class=\"wp-block-code\"><code>import requests\nfrom datetime import datetime, timedelta\n\nAPI_KEY = \"YOUR_API_KEY\"  # Get free at oddspapi.io\nBASE_URL = \"https:\/\/api.oddspapi.io\/v4\"<\/code><\/pre>\n<p>No extra libraries needed. Just <code>requests<\/code> and the standard library. <a href=\"https:\/\/oddspapi.io\">Grab your free API key<\/a> and drop it in.<\/p>\n<h3>Step 2: Get Today&#8217;s Fixtures<\/h3>\n<pre class=\"wp-block-code\"><code>def get_fixtures(sport_id=10):\n    \"\"\"Fetch today's fixtures. Sport 10 = Soccer.\"\"\"\n    today = datetime.now().strftime(\"%Y-%m-%d\")\n    tomorrow = (datetime.now() + timedelta(days=1)).strftime(\"%Y-%m-%d\")\n\n    response = requests.get(f\"{BASE_URL}\/fixtures\", params={\n        \"apiKey\": API_KEY,\n        \"sportId\": sport_id,\n        \"from\": today,\n        \"to\": tomorrow\n    })\n\n    fixtures = response.json()\n    # Filter to fixtures with odds available\n    return [f for f in fixtures if f.get(\"hasOdds\")]\n\n\nfixtures = get_fixtures()\nprint(f\"Found {len(fixtures)} fixtures with odds\")\nfor f in fixtures[:5]:\n    print(f\"  {f['participant1Name']} vs {f['participant2Name']} ({f['tournamentName']})\")<\/code><\/pre>\n<p>The <code>\/fixtures<\/code> endpoint returns a flat list of fixtures. We filter on <code>hasOdds<\/code> so we only scan matches that actually have pricing data from bookmakers.<\/p>\n<h3>Step 3: Fetch Odds from All Bookmakers<\/h3>\n<pre class=\"wp-block-code\"><code>def get_odds(fixture_id):\n    \"\"\"Get odds from all bookmakers for a fixture.\"\"\"\n    response = requests.get(f\"{BASE_URL}\/odds\", params={\n        \"apiKey\": API_KEY,\n        \"fixtureId\": fixture_id\n    })\n    return response.json()<\/code><\/pre>\n<p>One call, every bookmaker. The response contains a <code>bookmakerOdds<\/code> dictionary keyed by bookmaker slug (e.g., <code>pinnacle<\/code>, <code>bet365<\/code>, <code>singbet<\/code>). No pagination, no extra calls.<\/p>\n<h3>Step 4: Find the Best Price for Each Outcome<\/h3>\n<pre class=\"wp-block-code\"><code>def find_best_prices(odds_data, market_id=\"101\"):\n    \"\"\"Find the best price for each outcome across all bookmakers.\n\n    Market 101 = Full Time Result (1X2)\n    Outcomes: 101=Home, 102=Draw, 103=Away\n    \"\"\"\n    best = {}  # {outcome_id: {\"price\": float, \"bookmaker\": str}}\n\n    for slug, bookie in odds_data.get(\"bookmakerOdds\", {}).items():\n        market = bookie.get(\"markets\", {}).get(market_id)\n        if not market:\n            continue\n\n        for outcome_id, outcome in market.get(\"outcomes\", {}).items():\n            for player_id, player in outcome.get(\"players\", {}).items():\n                price = player.get(\"price\")\n                if price and (outcome_id not in best or price > best[outcome_id][\"price\"]):\n                    best[outcome_id] = {\n                        \"price\": price,\n                        \"bookmaker\": slug,\n                        \"outcome_id\": outcome_id\n                    }\n\n    return best<\/code><\/pre>\n<p>This is the core of the scanner. For each outcome in a market, we loop through every bookmaker and keep track of whoever is offering the highest price. The OddsPapi odds structure is nested: <code>bookmakerOdds &rarr; slug &rarr; markets &rarr; marketId &rarr; outcomes &rarr; outcomeId &rarr; players &rarr; 0 &rarr; price<\/code>.<\/p>\n<h3>Step 5: Calculate the Arbitrage Percentage<\/h3>\n<pre class=\"wp-block-code\"><code>def check_arb(best_prices):\n    \"\"\"Check if an arbitrage opportunity exists.\n\n    If the sum of implied probabilities &lt; 1.0, it's an arb.\n    Profit margin = (1 - sum) * 100\n    \"\"\"\n    if not best_prices:\n        return None\n\n    total_implied = sum(1 \/ bp[\"price\"] for bp in best_prices.values())\n    margin = (1 - total_implied) * 100\n\n    return {\n        \"is_arb\": total_implied &lt; 1.0,\n        \"margin\": margin,\n        \"total_implied\": total_implied,\n        \"prices\": best_prices\n    }<\/code><\/pre>\n<p>The formula is straightforward. Convert each best price to its implied probability (<code>1 \/ odds<\/code>), sum them up. If the total is under 1.0 (100%), you have an arb. The margin tells you how much guaranteed profit you can extract.<\/p>\n<h3>Step 6: Scan All Fixtures<\/h3>\n<pre class=\"wp-block-code\"><code>def scan_for_arbs(sport_id=10, market_id=\"101\"):\n    \"\"\"Scan all fixtures for arbitrage opportunities.\"\"\"\n    fixtures = get_fixtures(sport_id)\n    print(f\"Scanning {len(fixtures)} fixtures for arbs...\\n\")\n\n    arbs_found = []\n\n    for fixture in fixtures:\n        fid = fixture[\"fixtureId\"]\n        name = f\"{fixture['participant1Name']} vs {fixture['participant2Name']}\"\n\n        odds_data = get_odds(fid)\n        best_prices = find_best_prices(odds_data, market_id)\n        result = check_arb(best_prices)\n\n        if result and result[\"is_arb\"]:\n            arbs_found.append({\"fixture\": name, **result})\n            print(f\"ARB FOUND: {name}\")\n            print(f\"   Margin: {result['margin']:.2f}%\")\n            for oid, bp in result[\"prices\"].items():\n                print(f\"   Outcome {oid}: {bp['price']} @ {bp['bookmaker']}\")\n            print()\n        else:\n            overround = -result[\"margin\"] if result else 0\n            bookmakers = len(odds_data.get(\"bookmakerOdds\", {}))\n            print(f\"  {name}: {bookmakers} books, {overround:.1f}% overround\")\n\n    print(f\"\\n{'='*50}\")\n    print(f\"Scanned {len(fixtures)} fixtures\")\n    print(f\"Arbs found: {len(arbs_found)}\")\n\n    return arbs_found\n\n\n# Run the scanner\narbs = scan_for_arbs()<\/code><\/pre>\n<p>Run this and watch it scan every fixture. With 350+ bookmakers feeding prices, you will see arbs that scanners limited to 40 soft books will never detect.<\/p>\n<h2>Taking It Further: Multi-Market &amp; Real-Time Scanning<\/h2>\n<p>The scanner above covers the 1X2 (Full Time Result) market. But arbs hide in other markets too. Here is how to expand it.<\/p>\n<h3>Scan Multiple Markets<\/h3>\n<p>Loop through several markets to multiply your opportunities. Each market has its own set of outcomes and its own set of bookmaker pricing inefficiencies.<\/p>\n<pre class=\"wp-block-code\"><code>MARKETS = {\n    \"101\": \"Full Time Result (1X2)\",\n    \"1010\": \"Over\/Under 2.5 Goals\",\n    \"104\": \"Both Teams to Score\"\n}\n\nfor market_id, market_name in MARKETS.items():\n    print(f\"\\n--- {market_name} ---\")\n    arbs = scan_for_arbs(market_id=market_id)<\/code><\/pre>\n<p>Over\/Under and BTTS markets often have more arbs than 1X2 because they are two-outcome markets &mdash; fewer outcomes means the margin between bookmakers needs to be smaller to create an arb, and it happens more often.<\/p>\n<h3>Calculate Optimal Stakes<\/h3>\n<p>Once you find an arb, you need to know exactly how much to bet on each outcome to guarantee profit.<\/p>\n<pre class=\"wp-block-code\"><code>def calculate_stakes(best_prices, total_stake=100):\n    \"\"\"Calculate how much to bet on each outcome for guaranteed profit.\"\"\"\n    total_implied = sum(1 \/ bp[\"price\"] for bp in best_prices.values())\n\n    stakes = {}\n    for outcome_id, bp in best_prices.items():\n        implied = 1 \/ bp[\"price\"]\n        stake = (implied \/ total_implied) * total_stake\n        payout = stake * bp[\"price\"]\n        stakes[outcome_id] = {\n            \"bookmaker\": bp[\"bookmaker\"],\n            \"price\": bp[\"price\"],\n            \"stake\": round(stake, 2),\n            \"payout\": round(payout, 2)\n        }\n\n    profit = (1 \/ total_implied - 1) * total_stake\n\n    return {\"stakes\": stakes, \"profit\": round(profit, 2), \"roi\": round((1\/total_implied - 1) * 100, 2)}<\/code><\/pre>\n<p>The function distributes your total stake proportionally across outcomes so that every outcome pays out the same amount. The difference between total payout and total stake is your guaranteed profit.<\/p>\n<h3>Upgrade to WebSocket for Real-Time Detection<\/h3>\n<p>Polling the REST API every 30 seconds works for finding arbs, but most of them will have closed by the time you place your bets. The real edge comes from <strong>real-time WebSocket streaming<\/strong>. OddsPapi pushes odds changes to your bot the instant they happen, cutting your detection latency from 30 seconds to milliseconds.<\/p>\n<p>WebSocket access requires a Pro tier plan. For the full setup guide, check out our <a href=\"https:\/\/oddspapi.io\/blog\/websocket-odds-api-real-time-betting-data\">WebSocket Odds API tutorial<\/a>.<\/p>\n<h2>FAQ: Arbitrage Betting Bots<\/h2>\n<h3>Is arbitrage betting legal?<\/h3>\n<p>Yes, arbitrage betting is legal in most jurisdictions. You are simply placing bets at different bookmakers. However, bookmakers do not like arbers and may limit or close your accounts if they detect consistent arb activity. Using multiple accounts and varying your bet sizes can help extend account longevity.<\/p>\n<h3>How many bookmakers do I need for arbs?<\/h3>\n<p>The more bookmakers your scanner covers, the more arbs you will find. With 40 soft-only books (like The Odds API provides), you will find close to zero actionable arbs. With 350+ books including sharps like Pinnacle and Singbet, you will find several opportunities daily. The sharp-to-soft spread is where the real arbs live.<\/p>\n<h3>What sports have the most arbitrage opportunities?<\/h3>\n<p>Soccer has the most arbs because it has the widest bookmaker coverage globally. Tennis is also strong because it is a two-outcome market (no draw), which makes arbs more common. Niche markets like esports and regional leagues also produce arbs because fewer bookmakers price them efficiently.<\/p>\n<h3>Do I need a paid API plan?<\/h3>\n<p>The free tier (250 requests\/month) is enough to build and test your scanner. For production scanning across multiple sports and markets, you will want a paid plan for higher rate limits. For real-time WebSocket alerts, you need the Pro tier.<\/p>\n<h3>How long do arbitrage opportunities last?<\/h3>\n<p>Most arbs last seconds to a few minutes. Sharp bookmakers like Pinnacle move fast, and soft books adjust their lines accordingly. This is why polling-based scanners miss most arbs. Real-time WebSocket detection gives you the speed advantage you need.<\/p>\n<h3>Can I use this with Pinnacle?<\/h3>\n<p>Yes. OddsPapi aggregates odds from Pinnacle, Singbet, SBOBet, and other sharp bookmakers that most APIs do not carry. You do not need a Pinnacle commercial account or API key &mdash; OddsPapi handles the data aggregation for you.<\/p>\n<p><script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Is arbitrage betting legal?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes, arbitrage betting is legal in most jurisdictions. You are simply placing bets at different bookmakers. However, bookmakers may limit or close accounts if they detect consistent arb activity.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How many bookmakers do I need for arbs?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"With 40 soft-only books you will find close to zero actionable arbs. With 350+ books including sharps like Pinnacle and Singbet, you will find several opportunities daily.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"What sports have the most arbitrage opportunities?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Soccer has the most arbs due to the widest bookmaker coverage globally. Tennis is also strong as a two-outcome market. Niche markets like esports produce arbs because fewer bookmakers price them efficiently.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Do I need a paid API plan?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"The free tier (250 requests\/month) is enough to build and test your scanner. For production scanning, you will want a paid plan. Real-time WebSocket alerts require the Pro tier.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How long do arbitrage opportunities last?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Most arbs last seconds to a few minutes. Sharp bookmakers move fast, and soft books adjust accordingly. Real-time WebSocket detection gives you the speed advantage you need.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Can I use this with Pinnacle?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes. OddsPapi aggregates odds from Pinnacle, Singbet, SBOBet, and other sharp bookmakers. You do not need a Pinnacle commercial account \u2014 OddsPapi handles the data aggregation.\"\n      }\n    }\n  ]\n}\n<\/script><\/p>\n<h2>Stop Scraping. Start Scanning.<\/h2>\n<p>Every minute you spend scraping individual bookmaker sites is a minute you are not finding arbs. OddsPapi gives you 350+ bookmakers &mdash; including sharps like Pinnacle and Singbet &mdash; through one API call. Free historical data lets you backtest your strategy before risking real money. And when you are ready for production, WebSocket streaming gives you the sub-second latency that separates profitable arbers from the ones who are always a step behind.<\/p>\n<p><strong><a href=\"https:\/\/oddspapi.io\">Get Your Free API Key &rarr;<\/a><\/strong><\/p>\n<p><!--\nFocus Keyphrase: arbitrage betting bot python\nSEO Title: How to Build an Arbitrage Betting Bot with Python (Free API)\nMeta Description: Build a working arb scanner in Python using real odds from 350+ bookmakers. Detect arbitrage across Pinnacle, Bet365 & sharps. Free API tier included.\nSlug: arbitrage-betting-bot-python\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Build a working arb scanner in Python using real odds from 350+ bookmakers. Detect arbitrage across Pinnacle, Bet365 &#038; sharps. Free API tier included.<\/p>\n","protected":false},"author":2,"featured_media":2511,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[8,9,11,10],"class_list":["post-2509","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-free-api","tag-odds-api","tag-python","tag-sports-betting-api"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Build an Arbitrage Betting Bot with Python (Free API) | Odds API Development Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Build an Arbitrage Betting Bot with Python (Free API) | Odds API Development Blog\" \/>\n<meta property=\"og:description\" content=\"Build a working arb scanner in Python using real odds from 350+ bookmakers. Detect arbitrage across Pinnacle, Bet365 &amp; sharps. Free API tier included.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Odds API Development Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-03-17T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1429\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Odds API Writer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/oddspapi.io\/logo-v2.webp\" \/>\n<meta name=\"twitter:creator\" content=\"@oddspapiapi\" \/>\n<meta name=\"twitter:site\" content=\"@oddspapiapi\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Odds API Writer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"How to Build an Arbitrage Betting Bot with Python (Free API)\",\"datePublished\":\"2026-03-17T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\"},\"wordCount\":1229,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp\",\"keywords\":[\"Free API\",\"Odds API\",\"Python\",\"Sports Betting API\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\",\"name\":\"How to Build an Arbitrage Betting Bot with Python (Free API) | Odds API Development Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp\",\"datePublished\":\"2026-03-17T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"Arbitrage Betting Bot - OddsPapi API Blog\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Build an Arbitrage Betting Bot with Python (Free API)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\",\"url\":\"https:\/\/oddspapi.io\/blog\/\",\"name\":\"OddsPapi\",\"description\":\"Sports Odds APIs Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"alternateName\":\"Odds Papi\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/oddspapi.io\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\",\"name\":\"OddsPapi\",\"url\":\"https:\/\/oddspapi.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png\",\"width\":135,\"height\":135,\"caption\":\"OddsPapi\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/oddspapiapi\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\",\"name\":\"Odds API Writer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g\",\"caption\":\"Odds API Writer\"},\"url\":\"https:\/\/oddspapi.io\/blog\/author\/andy-lavelle\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Build an Arbitrage Betting Bot with Python (Free API) | Odds API Development Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/","og_locale":"en_US","og_type":"article","og_title":"How to Build an Arbitrage Betting Bot with Python (Free API) | Odds API Development Blog","og_description":"Build a working arb scanner in Python using real odds from 350+ bookmakers. Detect arbitrage across Pinnacle, Bet365 & sharps. Free API tier included.","og_url":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/","og_site_name":"Odds API Development Blog","article_published_time":"2026-03-17T10:00:00+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp","type":"image\/webp"}],"author":"Odds API Writer","twitter_card":"summary_large_image","twitter_image":"https:\/\/oddspapi.io\/logo-v2.webp","twitter_creator":"@oddspapiapi","twitter_site":"@oddspapiapi","twitter_misc":{"Written by":"Odds API Writer","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"How to Build an Arbitrage Betting Bot with Python (Free API)","datePublished":"2026-03-17T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/"},"wordCount":1229,"commentCount":0,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp","keywords":["Free API","Odds API","Python","Sports Betting API"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/","url":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/","name":"How to Build an Arbitrage Betting Bot with Python (Free API) | Odds API Development Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp","datePublished":"2026-03-17T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/03\/arbitrage-betting-bot-python-scaled.webp","width":2560,"height":1429,"caption":"Arbitrage Betting Bot - OddsPapi API Blog"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Build an Arbitrage Betting Bot with Python (Free API)"}]},{"@type":"WebSite","@id":"https:\/\/oddspapi.io\/blog\/#website","url":"https:\/\/oddspapi.io\/blog\/","name":"OddsPapi","description":"Sports Odds APIs Tutorials &amp; Guides","publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"alternateName":"Odds Papi","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/oddspapi.io\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/oddspapi.io\/blog\/#organization","name":"OddsPapi","url":"https:\/\/oddspapi.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png","width":135,"height":135,"caption":"OddsPapi"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/oddspapiapi"]},{"@type":"Person","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13","name":"Odds API Writer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g","caption":"Odds API Writer"},"url":"https:\/\/oddspapi.io\/blog\/author\/andy-lavelle\/"}]}},"_links":{"self":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2509","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/comments?post=2509"}],"version-history":[{"count":1,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2509\/revisions"}],"predecessor-version":[{"id":2510,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2509\/revisions\/2510"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/2511"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=2509"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=2509"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=2509"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}