{"id":2921,"date":"2026-05-25T10:00:00","date_gmt":"2026-05-25T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=2921"},"modified":"2026-05-09T13:38:42","modified_gmt":"2026-05-09T13:38:42","slug":"valorant-odds-api-vct-pinnacle-polymarket","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/","title":{"rendered":"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket &#038; 28+ Bookmakers"},"content":{"rendered":"<p>Looking for a <strong>Valorant odds API<\/strong>? PandaScore wants $200\/month for live VCT odds. The Odds API doesn&#8217;t cover Valorant at all. Bookmakers like Pinnacle don&#8217;t have a public API. So if you want to build a model, an arb scanner, or just track Champions Tour line movement, your options are: pay enterprise pricing, or scrape twelve different sites.<\/p>\n<p>There&#8217;s a third option. OddsPapi aggregates Valorant odds from 350+ bookmakers \u2014 including Pinnacle (the sharp benchmark), Polymarket (exchange pricing), DraftKings, BetMGM, and seven crypto books \u2014 into one JSON response. Free tier. No scraping. Free historical data for backtesting.<\/p>\n<p>This post shows you how to pull real Valorant Champions Tour odds in Python. Every code example is tested against the live API and uses real data from a Heretics vs BBL EMEA fixture (May 9, 2026, 28 books pricing the moneyline).<\/p>\n<h2>The Valorant Odds API Coverage Reality (Honest Numbers)<\/h2>\n<p>Before we get to code, let&#8217;s set expectations. We pulled every Valorant fixture across the next 10 days from <code>\/v4\/fixtures?sportId=61<\/code> and counted bookmakers per match.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Tournament<\/th>\n<th>Match<\/th>\n<th>Books<\/th>\n<th>Has Pinnacle?<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Champions Tour: EMEA<\/td>\n<td>Liquid vs Gentle Mates<\/td>\n<td>29<\/td>\n<td>\u2713<\/td>\n<\/tr>\n<tr>\n<td>Champions Tour: EMEA<\/td>\n<td>Heretics vs BBL<\/td>\n<td>28<\/td>\n<td>\u2713<\/td>\n<\/tr>\n<tr>\n<td>Champions Tour: Americas<\/td>\n<td>LOUD vs Leviatan<\/td>\n<td>27<\/td>\n<td>\u2713<\/td>\n<\/tr>\n<tr>\n<td>Champions Tour: Americas<\/td>\n<td>Sentinels vs NRG<\/td>\n<td>26<\/td>\n<td>\u2713<\/td>\n<\/tr>\n<tr>\n<td>Challengers DACH<\/td>\n<td>Eintracht Frankfurt vs FOKUS<\/td>\n<td>21<\/td>\n<td>\u2713<\/td>\n<\/tr>\n<tr>\n<td>Champions Tour: Americas<\/td>\n<td>G2 vs Cloud9<\/td>\n<td>5<\/td>\n<td>\u2713<\/td>\n<\/tr>\n<tr>\n<td>Challengers Spain<\/td>\n<td>Otakar vs Barca<\/td>\n<td>3<\/td>\n<td>\u2014<\/td>\n<\/tr>\n<tr>\n<td>Challengers France<\/td>\n<td>Joblife vs WIP<\/td>\n<td>0<\/td>\n<td>\u2014<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The pattern: <strong>VCT International Leagues (EMEA \/ Americas \/ Pacific) get 25\u201329 books per match. Challengers tier gets 0\u20135<\/strong>. Game Changers and tier-2 regional leagues are thin. If you&#8217;re building anything that depends on book diversity (line shopping, arb, value scanning), stick to the international leagues.<\/p>\n<p>One more honest note: <strong>Valorant on OddsPapi is moneyline-only right now<\/strong>. Match Winner (market ID 611) is the only market shipped across the catalog. No map handicaps, no map totals, no round handicaps. If you need that depth, you&#8217;re stuck with sportsbook scraping or PandaScore. For 80% of use cases \u2014 model building, line shopping, arb scanning, CLV tracking \u2014 moneyline from 28+ books is exactly what you want.<\/p>\n<h2>Old Way vs OddsPapi<\/h2>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Approach<\/th>\n<th>Books Covered<\/th>\n<th>Pinnacle?<\/th>\n<th>Crypto Books?<\/th>\n<th>Cost<\/th>\n<th>Historical Data<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>PandaScore<\/td>\n<td>~30<\/td>\n<td>\u2014<\/td>\n<td>Limited<\/td>\n<td>From $199\/mo<\/td>\n<td>Paid add-on<\/td>\n<\/tr>\n<tr>\n<td>The Odds API<\/td>\n<td>0 (no Valorant)<\/td>\n<td>n\/a<\/td>\n<td>n\/a<\/td>\n<td>n\/a<\/td>\n<td>n\/a<\/td>\n<\/tr>\n<tr>\n<td>Scraping individual books<\/td>\n<td>Whatever you build<\/td>\n<td>No (closed)<\/td>\n<td>You&#8217;ll get IP-banned<\/td>\n<td>Free + your time<\/td>\n<td>Build your own<\/td>\n<\/tr>\n<tr>\n<td><strong>OddsPapi<\/strong><\/td>\n<td><strong>29 distinct, 28+ per VCT match<\/strong><\/td>\n<td><strong>\u2713<\/strong><\/td>\n<td><strong>\u2713 (7 books)<\/strong><\/td>\n<td><strong>Free tier<\/strong><\/td>\n<td><strong>\u2713 Free<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<h2>Step 1: Authentication<\/h2>\n<p>Grab a <a href=\"https:\/\/oddspapi.io\/\">free API key<\/a>. Auth is a query parameter, not a header \u2014 this trips up people coming from RapidAPI-style services.<\/p>\n<pre class=\"wp-block-code\"><code>import requests\n\nAPI_KEY = \"YOUR_API_KEY\"\nBASE_URL = \"https:\/\/api.oddspapi.io\/v4\"\n\n# Smoke test\nr = requests.get(f\"{BASE_URL}\/sports\", params={\"apiKey\": API_KEY})\nprint(r.status_code)  # 200\n<\/code><\/pre>\n<h2>Step 2: Find Valorant Fixtures<\/h2>\n<p>Valorant&#8217;s <code>sportId<\/code> is <strong>61<\/strong>. The full sport name in the API is <code>ESport Valorant<\/code>, slug <code>esport-valorant<\/code>. Pull fixtures over a date window \u2014 max 10 days per call.<\/p>\n<pre class=\"wp-block-code\"><code>from datetime import datetime, timedelta, timezone\n\nnow = datetime.now(timezone.utc)\nto = now + timedelta(days=7)\n\nr = requests.get(f\"{BASE_URL}\/fixtures\", params={\n    \"apiKey\": API_KEY,\n    \"sportId\": 61,\n    \"from\": now.strftime(\"%Y-%m-%dT%H:%M:%S\"),\n    \"to\":   to.strftime(\"%Y-%m-%dT%H:%M:%S\"),\n})\nfixtures = [f for f in r.json() if f.get(\"hasOdds\")]\n\nfor f in fixtures:\n    print(f\"{f['tournamentName']:35s}  \"\n          f\"{f['participant1Name']} vs {f['participant2Name']}  \"\n          f\"start={f['startTime']}\")\n<\/code><\/pre>\n<p>Real output snippet from May 9, 2026:<\/p>\n<pre class=\"wp-block-code\"><code>Champions Tour: EMEA                 Heretics vs BBL              start=2026-05-09T15:15:00.000Z\nChampions Tour: EMEA                 Liquid vs Gentle Mates       start=2026-05-09T...\nChampions Tour: Americas             LOUD vs Leviatan             start=2026-05-09T...\nChampions Tour: Americas             Sentinels vs NRG             start=2026-05-09T...\nChallengers DACH                     Eintracht Frankfurt vs FOKUS start=2026-05-09T...\n<\/code><\/pre>\n<p>Note that each fixture object also exposes <code>externalProviders.pinnacleId<\/code>, which is useful if you&#8217;re cross-referencing with Pinnacle&#8217;s internal IDs from another data source.<\/p>\n<h2>Step 3: Pull Live Odds for a Match<\/h2>\n<p>One <code>\/v4\/odds<\/code> call returns every bookmaker&#8217;s pricing for a fixture. The response is nested \u2014 <code>bookmakerOdds \u2192 {slug} \u2192 markets \u2192 {marketId} \u2192 outcomes \u2192 {outcomeId} \u2192 players \u2192 \"0\" \u2192 price<\/code>.<\/p>\n<pre class=\"wp-block-code\"><code>fixture_id = \"pn619022571630262973\"  # Heretics vs BBL\n\nr = requests.get(f\"{BASE_URL}\/odds\", params={\n    \"apiKey\": API_KEY,\n    \"fixtureId\": fixture_id,\n})\ndata = r.json()\nbooks = data[\"bookmakerOdds\"]\nprint(f\"Books pricing this match: {len(books)}\")\nprint(f\"Bookmaker slugs: {sorted(books.keys())}\")\n<\/code><\/pre>\n<p>Real output:<\/p>\n<pre class=\"wp-block-code\"><code>Books pricing this match: 28\nBookmaker slugs: ['atg.se', 'bcgame', 'betmgm.co.uk', 'betplay', 'betrivers',\n                  'bingoal.be', 'blaze', 'casumo', 'draftkings', 'duel',\n                  'leovegas', 'paf', 'paf.es', 'pinnacle', 'polymarket',\n                  'rollbit', 'roobet', 'rushbet.co', 'scooore.be',\n                  'stake.bet.br', 'svenskaspel', 'unibet', 'unibet.be',\n                  'unibet.com.au', 'unibet.dk', 'unibet.ie', 'unibet.se', 'vertex']\n<\/code><\/pre>\n<p>That&#8217;s Pinnacle (sharp), Polymarket (exchange), DraftKings + BetRivers + BetMGM UK (regulated), seven crypto books (BCGame, Blaze, Stake, Rollbit, Roobet, Duel, Vertex), and a Unibet\/Kindred network across seven jurisdictions. From a single API call.<\/p>\n<h2>Step 4: Parse the Moneyline (Market 611)<\/h2>\n<p>Valorant&#8217;s only market is the Match Winner, ID <code>611<\/code>. Outcomes are <code>611<\/code> (participant1 \/ Home) and <code>612<\/code> (participant2 \/ Away). Here&#8217;s the safe parsing pattern:<\/p>\n<pre class=\"wp-block-code\"><code>def get_winner_prices(books, market_id=\"611\"):\n    \"\"\"Return {bookmaker: (home_price, away_price, active, changed_at)}.\"\"\"\n    out = {}\n    for slug, bk in books.items():\n        market = bk.get(\"markets\", {}).get(market_id)\n        if not market:\n            continue\n        outcomes = market.get(\"outcomes\", {})\n        home = outcomes.get(\"611\", {}).get(\"players\", {}).get(\"0\", {})\n        away = outcomes.get(\"612\", {}).get(\"players\", {}).get(\"0\", {})\n        out[slug] = (\n            home.get(\"price\"),\n            away.get(\"price\"),\n            home.get(\"active\") and away.get(\"active\"),\n            home.get(\"changedAt\"),\n        )\n    return out\n\nprices = get_winner_prices(books)\nfor slug, (h, a, active, ts) in sorted(prices.items()):\n    if active:\n        print(f\"{slug:25s}  home={h:>6}  away={a:>6}  updated={ts}\")\n<\/code><\/pre>\n<p>Sample output (Heretics vs BBL, captured 2026-05-09 at 13:33 UTC):<\/p>\n<pre class=\"wp-block-code\"><code>pinnacle                  home= 1.555  away=  2.47  updated=2026-05-09T09:44:47.301Z\npolymarket                home= 1.613  away= 2.564  updated=2026-05-09T13:33:52.353Z\ndraftkings                home= 1.570  away=  2.30  updated=2026-05-08T07:26:47.100Z\nbetmgm.co.uk              home= 1.530  away=  2.35  updated=2026-05-09T10:21:10.634Z\nbetrivers                 home= 1.530  away=  2.35  updated=2026-05-09T10:17:53.078Z\nunibet                    home= 1.530  away=  2.35  updated=2026-05-09T10:20:51.621Z\nvertex                    home= 1.563  away= 2.497  updated=2026-05-09T10:38:58.788Z\nbetplay                   home= 1.490  away=  2.35  updated=2026-05-09T10:21:19.368Z\nleovegas                  home= 1.490  away=  2.35  updated=2026-05-09T10:20:41.939Z\n<\/code><\/pre>\n<h2>Step 5: Calculate Vig and Find the Best Price<\/h2>\n<p>The whole point of pulling 28 books in one call is to <strong>price-shop<\/strong>. Here&#8217;s the vig calc and best-price scan in seven lines.<\/p>\n<pre class=\"wp-block-code\"><code>def vig(home, away):\n    return (1\/home + 1\/away - 1) * 100\n\nactive = {s: (h, a) for s, (h, a, act, _) in prices.items() if act and h and a}\nprint(f\"\\nVig per book (sorted, lowest = sharpest):\")\nfor slug, (h, a) in sorted(active.items(), key=lambda x: vig(*x[1])):\n    print(f\"  {slug:25s}  vig={vig(h,a):5.2f}%\")\n\nbest_home = max(active.items(), key=lambda x: x[1][0])\nbest_away = max(active.items(), key=lambda x: x[1][1])\nprint(f\"\\nBest Heretics: {best_home[1][0]} @ {best_home[0]}\")\nprint(f\"Best BBL:      {best_away[1][1]} @ {best_away[0]}\")\n<\/code><\/pre>\n<p>Real output:<\/p>\n<pre class=\"wp-block-code\"><code>Vig per book (sorted, lowest = sharpest):\n  polymarket                vig= 1.00%\n  vertex                    vig= 4.03%\n  pinnacle                  vig= 4.79%\n  draftkings                vig= 7.17%\n  unibet                    vig= 7.91%\n  betmgm.co.uk              vig= 7.91%\n  ...\n  paf.es                    vig=10.58%\n  rushbet.co                vig=10.58%\n\nBest Heretics (across sportsbooks): 1.613 @ polymarket\nBest BBL (across sportsbooks):      2.564 @ polymarket\n<\/code><\/pre>\n<p>Two things to notice:<\/p>\n<ol>\n<li><strong>Polymarket has 1.00% vig<\/strong> \u2014 by far the tightest pricing in the field. That&#8217;s because Polymarket is a peer-to-peer prediction market, not a sportsbook taking the other side. If you&#8217;re modeling Valorant, Polymarket&#8217;s implied probability is the cleanest signal we expose. (See our <a href=\"https:\/\/oddspapi.io\/blog\/polymarket-api-gamma-clob-json-format\/\">Polymarket Deep Dive<\/a> for how the <code>polymarket<\/code> slug works under the hood \u2014 including the <code>exchangeMeta.lay<\/code> side.)<\/li>\n<li><strong>Pinnacle de-vigs to ~61.4% \/ 38.6%<\/strong>. Soft books like betplay, leovegas, paf.es are pricing the favorite around 67\u201368% implied \u2014 meaning they&#8217;re charging an extra 6 percentage points of overround on top of Pinnacle&#8217;s number. That&#8217;s where +EV opportunities hide.<\/li>\n<\/ol>\n<p>For the line-shopping pattern in detail (with the same defensive filters across all sports), see our <a href=\"https:\/\/oddspapi.io\/blog\/line-shopping-python-best-odds\/\">Line Shopping in Python<\/a> tutorial \u2014 the <code>best_price()<\/code> helper there works on Valorant unchanged.<\/p>\n<h2>Step 6: Scan All Live VCT Matches at Once<\/h2>\n<p>Build a slate scanner: for every Valorant fixture with odds, pull the moneyline from every book, and surface mispricings vs Pinnacle.<\/p>\n<pre class=\"wp-block-code\"><code>import time\n\ndef scan_valorant_slate(api_key, days=7):\n    now = datetime.now(timezone.utc)\n    to = now + timedelta(days=days)\n    r = requests.get(f\"{BASE_URL}\/fixtures\", params={\n        \"apiKey\": api_key, \"sportId\": 61,\n        \"from\": now.strftime(\"%Y-%m-%dT%H:%M:%S\"),\n        \"to\":   to.strftime(\"%Y-%m-%dT%H:%M:%S\"),\n    })\n    fixtures = [f for f in r.json() if f.get(\"hasOdds\")]\n\n    for f in fixtures:\n        time.sleep(0.2)  # respect free-tier cooldown\n        rr = requests.get(f\"{BASE_URL}\/odds\", params={\n            \"apiKey\": api_key, \"fixtureId\": f[\"fixtureId\"]\n        })\n        books = rr.json().get(\"bookmakerOdds\", {})\n        prices = get_winner_prices(books)\n\n        pn = prices.get(\"pinnacle\")\n        if not (pn and pn[2] and pn[0] and pn[1]):\n            continue  # skip fixtures with no Pinnacle benchmark\n\n        # Pinnacle de-vig fair probability\n        s = 1\/pn[0] + 1\/pn[1]\n        fair_home, fair_away = (1\/pn[0])\/s, (1\/pn[1])\/s\n\n        match = f\"{f['participant1Name']} vs {f['participant2Name']}\"\n        print(f\"\\n{f['tournamentName']:30s} | {match}\")\n        print(f\"  Pinnacle fair: {1\/fair_home:.3f} \/ {1\/fair_away:.3f}  ({len(books)} books)\")\n\n        # Find +EV vs Pinnacle de-vig (skip crypto books \u2014 see note below)\n        SKIP = {\"bcgame\", \"blaze\", \"rollbit\", \"roobet\", \"duel\", \"vertex\", \"stake\"}\n        for slug, (h, a, act, _) in prices.items():\n            if slug in SKIP or slug == \"pinnacle\" or not act:\n                continue\n            ev_h = (h * fair_home - 1) * 100\n            ev_a = (a * fair_away - 1) * 100\n            if ev_h > 1 or ev_a > 1:\n                print(f\"    +EV {slug:20s}  home {ev_h:+5.2f}%  away {ev_a:+5.2f}%\")\n\nscan_valorant_slate(API_KEY, days=7)\n<\/code><\/pre>\n<p><strong>One gotcha worth flagging:<\/strong> a few crypto books (BCGame, Blaze, Rollbit) occasionally ship Valorant outcome IDs in reversed order \u2014 they&#8217;ll list the away team&#8217;s price under outcome 611. We filter them out of the +EV scanner above as a safety measure. The fix is to cross-reference each book&#8217;s <code>bookmakerOutcomeId<\/code> field (which says <code>\"home\"<\/code> or <code>\"away\"<\/code>) when in doubt, or simply restrict your scanner to regulated books for production use. Pinnacle, Polymarket, DraftKings, BetRivers, BetMGM, Unibet, and the Kindred network all parse correctly.<\/p>\n<h2>Step 7: Free Historical Odds for Backtesting<\/h2>\n<p>This is the kill shot competitors charge $200+\/month for. Pull the full price history of any Valorant fixture&#8217;s moneyline from <code>\/v4\/historical-odds<\/code>:<\/p>\n<pre class=\"wp-block-code\"><code>r = requests.get(f\"{BASE_URL}\/historical-odds\", params={\n    \"apiKey\": API_KEY,\n    \"fixtureId\": \"pn619022571630262973\",\n    \"bookmakers\": \"pinnacle,polymarket,draftkings\",  # max 3 per call\n})\ndata = r.json()\n\n# NOTE: historical endpoint key is `bookmakers`, not `bookmakerOdds`,\n# and players[\"0\"] is a LIST of price snapshots, not a single dict.\nfor slug, bk in data[\"bookmakers\"].items():\n    snapshots = bk[\"markets\"][\"611\"][\"outcomes\"][\"611\"][\"players\"][\"0\"]\n    print(f\"\\n{slug}: {len(snapshots)} price changes for Heretics\")\n    for snap in snapshots[-5:]:\n        print(f\"  {snap['createdAt']}  price={snap['price']}\")\n<\/code><\/pre>\n<p>Loop the call with different bookmaker groupings and merge the responses if you need more than three books at a time. We&#8217;ve covered the full historical-odds export pattern (CSV \/ Excel) in our <a href=\"https:\/\/oddspapi.io\/blog\/historical-odds-csv-excel-backtesting\/\">Historical Odds Export<\/a> guide if you want to feed this into pandas for backtesting.<\/p>\n<h2>What to Build With This<\/h2>\n<ul>\n<li><strong>VCT line-movement tracker<\/strong> \u2014 poll <code>\/odds<\/code> every 60s during a match and log every price change. Hat tip to our <a href=\"https:\/\/oddspapi.io\/blog\/steam-move-detector-python\/\">Steam Move Detector<\/a> if you want a sharp-money alert bot pattern.<\/li>\n<li><strong>Polymarket vs sportsbook arb scanner<\/strong> \u2014 Polymarket&#8217;s 1% vig means it&#8217;s frequently the best price on at least one side. When sportsbooks lag the Polymarket line, there&#8217;s a real arb window.<\/li>\n<li><strong>Backtest a Valorant rating model<\/strong> \u2014 pull historical odds for the last 100 VCT matches, compare your model&#8217;s predicted probabilities to the Pinnacle closing line, calculate CLV. Free to do; competitors charge $200\/mo for this.<\/li>\n<li><strong>Real-time dashboard<\/strong> \u2014 build a Streamlit page that scans the live VCT slate every minute and surfaces best price + line movement. Same pattern as our <a href=\"https:\/\/oddspapi.io\/blog\/odds-comparison-dashboard-python-streamlit\/\">Streamlit Odds Dashboard<\/a>.<\/li>\n<\/ul>\n<h2>FAQ<\/h2>\n<h3>Does OddsPapi cover the full Valorant Champions Tour?<\/h3>\n<p>Yes \u2014 both the international leagues (EMEA, Americas, Pacific) and the Challengers tier are in the fixture feed. International league matches typically have 25\u201329 books pricing the moneyline; Challengers and Game Changers events get 0\u20135 books and shouldn&#8217;t be relied on for line shopping.<\/p>\n<h3>Why is Polymarket showing different odds than Pinnacle?<\/h3>\n<p>Polymarket is a peer-to-peer prediction market, not a sportsbook. Their pricing represents the market&#8217;s implied probability after a near-zero margin, while Pinnacle bakes in roughly 5% vig as a sharp sportsbook. Both are &#8220;sharp&#8221; signals, but they&#8217;re not the same number. OddsPapi ships Polymarket prices already converted to decimal odds \u2014 the <code>polymarket<\/code> slug behaves like any other bookmaker in the response.<\/p>\n<h3>Can I get map-by-map handicaps and totals?<\/h3>\n<p>Not currently. Valorant on OddsPapi is moneyline-only \u2014 Match Winner (market ID 611) is the only market shipped across the full bookmaker network. If your use case strictly needs map handicaps or round totals, you&#8217;ll need to scrape directly from Pinnacle \/ DraftKings, or add a paid esports-specialist provider on top.<\/p>\n<h3>What&#8217;s the difference between this and the OddsPapi esports guide?<\/h3>\n<p>The <a href=\"https:\/\/oddspapi.io\/blog\/esports-odds-api-guide-how-to-get-pinnacle-cs2-lol-data-for-free\/\">Esports Odds API guide<\/a> covers CS2, LoL, and Dota 2 \u2014 the older esports cluster. Valorant has its own dedicated <code>sportId<\/code> (61) with VCT-specific tournament feeds, which is why it gets a separate post. The code pattern is the same; the sport ID and tournament names are what change.<\/p>\n<h3>Is the free tier enough for a Valorant scanner?<\/h3>\n<p>For most use cases, yes. The free tier limits you to roughly one call per second per endpoint and 250 free requests\/day. A VCT slate scanner that polls every 60 seconds across 5 live matches uses well under that. WebSocket push (paid tier) is only worth it if you need sub-second latency \u2014 see our <a href=\"https:\/\/oddspapi.io\/blog\/websocket-odds-api-real-time-betting-data\/\">WebSocket Odds API<\/a> post for the latency tradeoffs.<\/p>\n<h2>Stop Scraping. Get Your Free API Key.<\/h2>\n<p>One <code>requests.get()<\/code> call. 28+ bookmakers. Pinnacle, Polymarket, DraftKings, BetMGM, BetRivers, Unibet, seven crypto books \u2014 all on the free tier. Free historical odds for backtesting. No scraping, no IP-bans, no enterprise sales call.<\/p>\n<p><a href=\"https:\/\/oddspapi.io\/\"><strong>Get your free OddsPapi API key \u2192<\/strong><\/a><\/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\": \"Does OddsPapi cover the full Valorant Champions Tour?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes \u2014 both the international leagues (EMEA, Americas, Pacific) and the Challengers tier are in the fixture feed. International league matches typically have 25\u201329 books pricing the moneyline; Challengers and Game Changers events get 0\u20135 books and shouldn't be relied on for line shopping.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why is Polymarket showing different odds than Pinnacle on Valorant?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Polymarket is a peer-to-peer prediction market, not a sportsbook. Their pricing represents the market's implied probability after a near-zero margin, while Pinnacle bakes in roughly 5% vig as a sharp sportsbook. Both are sharp signals, but they're not the same number. OddsPapi ships Polymarket prices already converted to decimal odds.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Can I get Valorant map handicaps and totals via the OddsPapi API?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Not currently. Valorant on OddsPapi is moneyline-only \u2014 Match Winner (market ID 611) is the only market shipped across the full bookmaker network. If your use case strictly needs map handicaps or round totals, you'll need to scrape directly from Pinnacle \/ DraftKings, or add a paid esports-specialist provider on top.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"What's the difference between this and the OddsPapi esports guide?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"The Esports Odds API guide covers CS2, LoL, and Dota 2. Valorant has its own dedicated sportId (61) with VCT-specific tournament feeds, which is why it gets a separate post. The code pattern is the same; the sport ID and tournament names are what change.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Is the OddsPapi free tier enough for a Valorant scanner?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"For most use cases, yes. The free tier limits you to roughly one call per second per endpoint and 250 free requests\/day. A VCT slate scanner that polls every 60 seconds across 5 live matches uses well under that. WebSocket push (paid tier) is only worth it if you need sub-second latency.\"\n      }\n    }\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: valorant odds api\nSEO Title: Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket & 28+ Books\nMeta Description: Pull live Valorant Champions Tour odds from Pinnacle, Polymarket & 28+ bookmakers in one Python call. Free tier, no scraping, free historical data.\nSlug: valorant-odds-api-vct-pinnacle-polymarket\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pull live Valorant Champions Tour odds from Pinnacle, Polymarket &#038; 28+ bookmakers in one Python call. Free tier, no scraping, free historical data.<\/p>\n","protected":false},"author":2,"featured_media":2922,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[13,8,9,11,68],"class_list":["post-2921","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-esports","tag-free-api","tag-odds-api","tag-python","tag-valorant"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket &amp; 28+ Bookmakers | OddsPapi 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\/valorant-odds-api-vct-pinnacle-polymarket\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket &amp; 28+ Bookmakers | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"Pull live Valorant Champions Tour odds from Pinnacle, Polymarket &amp; 28+ bookmakers in one Python call. Free tier, no scraping, free historical data.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-25T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-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=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket &#038; 28+ Bookmakers\",\"datePublished\":\"2026-05-25T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/\"},\"wordCount\":1386,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp\",\"keywords\":[\"Esports\",\"Free API\",\"Odds API\",\"Python\",\"Valorant\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/\",\"name\":\"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket & 28+ Bookmakers | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp\",\"datePublished\":\"2026-05-25T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"Valorant Odds API - OddsPapi API Blog\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket &#038; 28+ Bookmakers\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\",\"url\":\"https:\/\/oddspapi.io\/blog\/\",\"name\":\"OddsPapi\",\"description\":\"Sports Odds API 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":"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket & 28+ Bookmakers | OddsPapi 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\/valorant-odds-api-vct-pinnacle-polymarket\/","og_locale":"en_US","og_type":"article","og_title":"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket & 28+ Bookmakers | OddsPapi Blog","og_description":"Pull live Valorant Champions Tour odds from Pinnacle, Polymarket & 28+ bookmakers in one Python call. Free tier, no scraping, free historical data.","og_url":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-05-25T10:00:00+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-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":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket &#038; 28+ Bookmakers","datePublished":"2026-05-25T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/"},"wordCount":1386,"commentCount":0,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp","keywords":["Esports","Free API","Odds API","Python","Valorant"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/","url":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/","name":"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket & 28+ Bookmakers | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp","datePublished":"2026-05-25T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/valorant-odds-api-vct-pinnacle-polymarket-scaled.webp","width":2560,"height":1429,"caption":"Valorant Odds API - OddsPapi API Blog"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/valorant-odds-api-vct-pinnacle-polymarket\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"Valorant Odds API: Real-Time VCT Odds from Pinnacle, Polymarket &#038; 28+ Bookmakers"}]},{"@type":"WebSite","@id":"https:\/\/oddspapi.io\/blog\/#website","url":"https:\/\/oddspapi.io\/blog\/","name":"OddsPapi","description":"Sports Odds API 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\/2921","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=2921"}],"version-history":[{"count":1,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2921\/revisions"}],"predecessor-version":[{"id":2923,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2921\/revisions\/2923"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/2922"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=2921"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=2921"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=2921"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}