{"id":3971,"date":"2026-09-21T10:00:00","date_gmt":"2026-09-21T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=3971"},"modified":"2026-09-10T13:27:34","modified_gmt":"2026-09-10T13:27:34","slug":"cs2-odds-api","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/","title":{"rendered":"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs"},"content":{"rendered":"<p>Pull one Counter-Strike 2 match off the OddsPapi <strong>CS2 odds API<\/strong> and you get a wide board. Magic v Alliance at FISSURE Playground on 10 September 2026 returned <strong>155 bookmakers<\/strong>. Another PGL Masters Bucharest fixture returned 149. Across 41 CS2 fixtures with odds in a nine-day window, the median was 91 books.<\/p>\n<p>Then you parse it, and the same market name comes back fifteen times. <code>Maps Handicap<\/code> is fifteen separate market IDs, one per rung from -3.5 to +3.5. <code>Total Maps Over Under<\/code> is another seven, from 2.5 to 8.5. The line that separates them sits in the <code>handicap<\/code> field of <code>\/v4\/markets<\/code>, not in the price object. Key your parser on the market name and you merge fifteen different bets into one.<\/p>\n<h2>What the CS2 Catalogue Holds<\/h2>\n<p>Counter-Strike 2 is <code>sportId<\/code> 17. Its catalogue is 28 market IDs, and 22 of them belong to the two ladders. Every number in this post comes from live calls made on 10 September 2026.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Market name<\/th>\n<th>Market IDs<\/th>\n<th>Lines<\/th>\n<th>Period<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Winner<\/td>\n<td><code>171<\/code><\/td>\n<td>0.0<\/td>\n<td>series<\/td>\n<\/tr>\n<tr>\n<td>Total Maps Over Under<\/td>\n<td><code>173<\/code>, <code>175<\/code>, <code>177<\/code>, <code>179<\/code>, <code>1711<\/code>, <code>1713<\/code>, <code>1715<\/code><\/td>\n<td>2.5 to 8.5<\/td>\n<td>series<\/td>\n<\/tr>\n<tr>\n<td>Maps Handicap<\/td>\n<td><code>1717<\/code> to <code>1745<\/code>, odd numbers<\/td>\n<td>-3.5 to +3.5 in 0.5 steps<\/td>\n<td>series<\/td>\n<\/tr>\n<tr>\n<td>First to Fifth Map Winner (incl. overtime)<\/td>\n<td><code>1747<\/code>, <code>1749<\/code>, <code>1751<\/code>, <code>1753<\/code>, <code>1755<\/code><\/td>\n<td>0.0<\/td>\n<td>p1 to p5<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>This is the mirror image of the trap in our <a href=\"https:\/\/oddspapi.io\/blog\/boxing-odds-api\/\">boxing odds API post<\/a>. There, three market IDs carry the same bet and you merge them. Here, fifteen IDs share one name and carry fifteen different bets, so you split them on <code>handicap<\/code> and keep them apart.<\/p>\n<h2>Old Way vs OddsPapi<\/h2>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Task<\/th>\n<th>Scraping two or three sportsbooks<\/th>\n<th>OddsPapi <code>\/v4<\/code><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Books on a tier-1 CS2 match<\/td>\n<td>2 to 3<\/td>\n<td>Up to 155, median 91 across 41 fixtures<\/td>\n<\/tr>\n<tr>\n<td>Map handicap ladder<\/td>\n<td>Reverse-engineer each site&#8217;s HTML<\/td>\n<td>15 market IDs with a typed <code>handicap<\/code> value<\/td>\n<\/tr>\n<tr>\n<td>Sharp anchor<\/td>\n<td>Pinnacle, if the page loads<\/td>\n<td>Pinnacle, Kalshi, Polymarket and Betfair Exchange in one payload<\/td>\n<\/tr>\n<tr>\n<td>Grading a finished Bo3<\/td>\n<td>Write your own rules per market<\/td>\n<td><code>\/v4\/settlements<\/code> returns WIN, LOSE or PUSH per outcome<\/td>\n<\/tr>\n<tr>\n<td>Historical prices<\/td>\n<td>Log it yourself from today<\/td>\n<td>Free, every recorded snapshot, three books per call<\/td>\n<\/tr>\n<tr>\n<td>Cost to start<\/td>\n<td>Your weekends<\/td>\n<td>Free tier, no card<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<h2>Step 1: Find the Circuits That Are Running<\/h2>\n<p>Do not discover CS2 events from <code>\/v4\/tournaments<\/code>. The endpoint returned 350 CS2 tournament rows on 10 September and marked four of them with <code>futureFixtures &gt; 0<\/code>. Eleven circuits had fixtures on the nine-day window, and ten of those eleven reported <code>futureFixtures<\/code> as zero, PGL Masters Bucharest among them. Group <code>\/v4\/fixtures<\/code> on <code>tournamentId<\/code> instead.<\/p>\n<pre class=\"wp-block-code\"><code>import os, requests, collections, datetime as dt\n\nAPI_KEY = os.environ[\"ODDSPAPI_API_KEY\"]\nBASE = \"https:\/\/api.oddspapi.io\/v4\"\nCS2 = 17\n\ntoday = dt.date.today()\nr = requests.get(f\"{BASE}\/fixtures\", params={\n    \"apiKey\": API_KEY, \"sportId\": CS2,\n    \"from\": today.isoformat(),\n    \"to\": (today + dt.timedelta(days=9)).isoformat(),\n})\nr.raise_for_status()\nfixtures = r.json()\n\ncircuits = collections.Counter(\n    (f[\"tournamentId\"], f[\"tournamentName\"]) for f in fixtures\n)\nprint(f\"{len(fixtures)} fixtures, {sum(1 for f in fixtures if f['hasOdds'])} with odds\")\nfor (tid, name), n in circuits.most_common():\n    print(f\"  {n:&gt;3}  {name}  ({tid})\")<\/code><\/pre>\n<p>Output on 10 September 2026:<\/p>\n<pre class=\"wp-block-code\"><code>50 fixtures, 41 with odds\n   11  PGL Masters Bucharest  (49212)\n    8  FISSURE Playground  (46097)\n    8  Thunderpick World Championship  (41296)\n    6  CCT European Series  (51122)\n    4  United21  (44609)\n    4  CCT Contenders Europe  (51054)\n    3  CCT Europe Challengers  (51210)\n    2  1win Private Club  (52934)\n    2  ESEA League Europe  (51004)\n    1  NODWIN Clutch Series  (49568)\n    1  NSTLGA League  (51976)<\/code><\/pre>\n<p>Two constraints on that call. Without a <code>tournamentId<\/code>, a <code>from<\/code>\/<code>to<\/code> range wider than ten days returns <code>400 INVALID_PARAMETER<\/code>. And <code>to<\/code> is a midnight-UTC instant, so set it to the day after the last day you want.<\/p>\n<h2>Step 2: Build the Ladder Map<\/h2>\n<p>The <code>sportId<\/code> parameter on <code>\/v4\/markets<\/code> is a no-op. The endpoint returns all 33,115 definitions and you filter client-side. Each row carries <code>marketName<\/code>, <code>handicap<\/code>, <code>period<\/code> and the outcome list, and the pair <code>(marketName, handicap)<\/code> is what identifies the bet.<\/p>\n<pre class=\"wp-block-code\"><code>catalogue = requests.get(f\"{BASE}\/markets\", params={\"apiKey\": API_KEY}).json()\ncs2 = {str(m[\"marketId\"]): m for m in catalogue if m[\"sportId\"] == CS2}\n\nfor mid, m in sorted(cs2.items(), key=lambda kv: (kv[1][\"marketName\"], kv[1][\"handicap\"])):\n    print(f\"  {mid:&gt;5}  {m['marketName']:&lt;34} line {m['handicap']:&gt;5}  period {m['period']}\")\n\nhandicaps = {m[\"handicap\"]: mid for mid, m in cs2.items()\n             if m[\"marketName\"] == \"Maps Handicap\"}\ntotals = {m[\"handicap\"]: mid for mid, m in cs2.items()\n          if m[\"marketName\"] == \"Total Maps Over Under\"}\nprint(\"Maps Handicap rungs:\", sorted(handicaps))\nprint(\"Total Maps rungs:   \", sorted(totals))<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>28 Counter-Strike 2 market IDs\n   1717  Maps Handicap                      line  -3.5  period result\n   1719  Maps Handicap                      line  -3.0  period result\n   ...\n   1745  Maps Handicap                      line   3.5  period result\n    173  Total Maps Over Under              line   2.5  period result\n    ...\n    171  Winner                             line   0.0  period result\n\nMaps Handicap rungs: [-3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5]\nTotal Maps rungs:    [2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5]<\/code><\/pre>\n<p>Read the outcome names from the catalogue too. The two legs of <code>Maps Handicap<\/code> are named <code>1<\/code> and <code>2<\/code>, and their order inside the <code>outcomes<\/code> array flips between rungs. Market <code>1717<\/code> lists outcome 1718 first; market <code>1725<\/code> lists outcome 1725 first. Match on <code>outcomeName<\/code> and never on array position.<\/p>\n<h2>Step 3: Read the Board<\/h2>\n<p>One <code>\/v4\/odds<\/code> call returns every book on the fixture. Three filters turn the raw payload into quotes you can price against: the book-level <code>suspended<\/code> flag, the market-level <code>marketActive<\/code> flag, and the price-level <code>active<\/code> flag. Drop any slug containing <code>+<\/code> and the <code>demo<\/code> slug as well, because those are internal test feeds.<\/p>\n<pre class=\"wp-block-code\"><code>import statistics\n\ndef read_board(fixture_id, catalogue):\n    \"\"\"Return {market_id: {slug: {outcome_id: price}}} for two-sided active quotes.\"\"\"\n    r = requests.get(f\"{BASE}\/odds\",\n                     params={\"apiKey\": API_KEY, \"fixtureId\": fixture_id})\n    r.raise_for_status()\n    board = {}\n    for slug, book in (r.json().get(\"bookmakerOdds\") or {}).items():\n        if \"+\" in slug or slug == \"demo\":\n            continue\n        if book.get(\"suspended\"):\n            continue\n        for mid, market in (book.get(\"markets\") or {}).items():\n            if not market.get(\"marketActive\"):\n                continue\n            legs = {}\n            for oid, outcome in (market.get(\"outcomes\") or {}).items():\n                price = (outcome.get(\"players\") or {}).get(\"0\")\n                if price and price.get(\"active\") and price.get(\"price\"):\n                    legs[oid] = price[\"price\"]\n            if len(legs) == len(catalogue[mid][\"outcomes\"]):\n                board.setdefault(mid, {})[slug] = legs\n    return board\n\nboard = read_board(\"id1704921274528890\", cs2)   # Fluxo v Dendele, PGL Masters Bucharest\n\nfor mid, quotes in sorted(board.items(), key=lambda kv: -len(kv[1])):\n    m = cs2[mid]\n    tuples = {tuple(sorted(q.items())) for q in quotes.values()}\n    margins = [sum(1 \/ p for p in q.values()) - 1 for q in quotes.values()]\n    print(f\"{mid:&gt;5} {m['marketName']:&lt;34} line {m['handicap']:&gt;5} | \"\n          f\"{len(quotes):&gt;3} books -&gt; {len(tuples):&gt;3} distinct | \"\n          f\"median margin {100 * statistics.median(margins):.2f}%\")<\/code><\/pre>\n<p>Fluxo v Dendele carried 134 books and 26 market IDs. After the three filters, seven markets survive:<\/p>\n<pre class=\"wp-block-code\"><code>  171 Winner                             line   0.0 | 132 books -&gt;  21 distinct | median margin 7.96%\n 1749 Second Map Winner (incl. overtime) line   0.0 | 124 books -&gt;  22 distinct | median margin 6.99%\n 1747 First Map Winner (incl. overtime)  line   0.0 | 124 books -&gt;  21 distinct | median margin 6.99%\n  173 Total Maps Over Under              line   2.5 | 120 books -&gt;  22 distinct | median margin 7.19%\n 1737 Maps Handicap                      line   1.5 | 118 books -&gt;  21 distinct | median margin 7.93%\n 1725 Maps Handicap                      line  -1.5 |  81 books -&gt;  14 distinct | median margin 8.15%\n 1751 Third Map Winner (incl. overtime)  line   0.0 |  65 books -&gt;  13 distinct | median margin 7.07%<\/code><\/pre>\n<p>Those seven are the series markets a best-of-three can settle: the winner, the 2.5 map total, the +\/-1.5 map handicap, and a winner for each of the three maps. Across 18 pre-match CS2 fixtures measured on 10 September, they ran <strong>97.1% active<\/strong>, or 12,266 live prices out of 12,634. The other nineteen rungs of the two ladders carried 5,258 posted prices across those same 18 fixtures and none of them was flagged <code>active<\/code>. The <code>active<\/code> filter is what separates a tradeable board from a menu. Our <a href=\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\">NFL alternate lines post<\/a> runs the same measurement on a 1,679-market American football board.<\/p>\n<p>Note the dedupe line. 132 distinct slugs quoted the Fluxo v Dendele winner and they collapse to 21 distinct price tuples, an 84% collapse. Across 14 deep boards the median collapse was 72%. Count books before you dedupe and a consensus price counts one trading desk twenty times. The <code>cloneOf<\/code> field does not catch this, so compare the price tuple itself.<\/p>\n<h2>Step 4: Find the Tight Prices<\/h2>\n<p>Margin ranking works on any two-legged market and does not care which leg is which: <code>1\/a + 1\/b - 1<\/code>. Run it across 14 deep CS2 boards and the prediction markets sit at the top.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Bookmaker<\/th>\n<th>Fixtures quoted (of 14)<\/th>\n<th>Median margin on market <code>171<\/code><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>polymarket.us<\/code><\/td>\n<td>11<\/td>\n<td>1.00%<\/td>\n<\/tr>\n<tr>\n<td><code>polymarket<\/code><\/td>\n<td>10<\/td>\n<td>1.01%<\/td>\n<\/tr>\n<tr>\n<td><code>kalshi<\/code><\/td>\n<td>9<\/td>\n<td>1.03%<\/td>\n<\/tr>\n<tr>\n<td><code>duel<\/code><\/td>\n<td>12<\/td>\n<td>3.49%<\/td>\n<\/tr>\n<tr>\n<td><code>1xbet<\/code><\/td>\n<td>14<\/td>\n<td>5.41%<\/td>\n<\/tr>\n<tr>\n<td>Board median, 63 books<\/td>\n<td>&#8211;<\/td>\n<td>6.46%<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Polymarket and Kalshi appeared on all 14 boards, Pinnacle on 7 and Betfair Exchange on 3. On esports the prediction markets are the anchor you can rely on being there, which is the same pattern our <a href=\"https:\/\/oddspapi.io\/blog\/lol-odds-api\/\">League of Legends odds API post<\/a> found on the LEC and LCK board. De-vig the deduped consensus rather than any single book, and use the <a href=\"https:\/\/oddspapi.io\/blog\/consensus-odds-fair-odds-calculator-python\/\">consensus odds method<\/a> to get there.<\/p>\n<h2>Step 5: Grade the Ladder<\/h2>\n<p><code>\/v4\/scores<\/code> returns the map score of a finished series, and <code>\/v4\/settlements<\/code> returns WIN, LOSE or PUSH for every outcome. Together they let you check your own handicap logic against the feed before you trust it on money.<\/p>\n<p>The rule for <code>Maps Handicap<\/code> is one line. Add the market&#8217;s <code>handicap<\/code> value to participant 1&#8217;s map margin. Positive is a win, negative is a loss, zero is a push.<\/p>\n<pre class=\"wp-block-code\"><code>import time\n\ndef grade_handicap(map_margin, line):\n    \"\"\"map_margin = participant1 maps - participant2 maps.\"\"\"\n    edge = map_margin + line\n    return \"PUSH\" if edge == 0 else (\"WIN\" if edge &gt; 0 else \"LOSE\")\n\nFIXTURE = \"id1704609774517440\"   # G2 Esports v 9Z Team, FISSURE Playground\n\nscores = requests.get(f\"{BASE}\/scores\",\n                      params={\"apiKey\": API_KEY, \"fixtureId\": FIXTURE}).json()\nresult = scores[\"scores\"][\"periods\"][\"result\"]\nmargin = result[\"participant1Score\"] - result[\"participant2Score\"]\nprint(f\"map score {result['participant1Score']}-{result['participant2Score']}, margin {margin:+d}\")\n\ntime.sleep(2)\nsettled = requests.get(f\"{BASE}\/settlements\",\n                       params={\"apiKey\": API_KEY, \"fixtureId\": FIXTURE}).json()\n\nfor mid, market in settled[\"markets\"].items():\n    meta = cs2[mid]\n    if meta[\"marketName\"] != \"Maps Handicap\":\n        continue\n    leg1 = next(o for o in meta[\"outcomes\"] if o[\"outcomeName\"] == \"1\")\n    feed = market[\"outcomes\"][str(leg1[\"outcomeId\"])][\"players\"][\"0\"][\"result\"]\n    mine = grade_handicap(margin, meta[\"handicap\"])\n    print(f\"  {mid:&gt;5}  line {meta['handicap']:&gt;5}  feed {feed:&lt;5}  mine {mine:&lt;5}  \"\n          f\"{'ok' if feed == mine else 'MISMATCH'}\")<\/code><\/pre>\n<p>G2 Esports beat 9Z Team 2-1, a margin of +1:<\/p>\n<pre class=\"wp-block-code\"><code>map score 2-1, margin +1\n   1717  line  -3.5  feed LOSE   mine LOSE   ok\n   1721  line  -2.5  feed LOSE   mine LOSE   ok\n   1725  line  -1.5  feed LOSE   mine LOSE   ok\n   1727  line  -1.0  feed PUSH   mine PUSH   ok\n   1729  line  -0.5  feed WIN    mine WIN    ok\n   1737  line   1.5  feed WIN    mine WIN    ok\n   1745  line   3.5  feed WIN    mine WIN    ok\n15 handicap rungs checked<\/code><\/pre>\n<p>All fifteen rungs matched. The same script on Magic v Parivision, a 2-0 series, moved the push to <code>1723<\/code> at -2.0 and matched all fifteen again. Wrap the <code>\/settlements<\/code> call in a retry: it returns a transient 429 under about two seconds of spacing.<\/p>\n<h2>Step 6: Pull the History for Free<\/h2>\n<p><code>\/v4\/historical-odds<\/code> is on the free tier and returns every recorded snapshot. It takes at most three bookmakers per call, and one unreadable slug fails the whole batch, so loop three at a time. Polymarket and Betfair Exchange need one bookmaker plus exactly one <code>outcomeId<\/code>.<\/p>\n<pre class=\"wp-block-code\"><code>import datetime as dt\n\nSTART = dt.datetime(2026, 9, 10, 3, 0, tzinfo=dt.timezone.utc)\n\nr = requests.get(f\"{BASE}\/historical-odds\", params={\n    \"apiKey\": API_KEY, \"fixtureId\": FIXTURE,\n    \"bookmakers\": \"pinnacle,1xbet,stake\",\n})\nr.raise_for_status()\n\nfor slug, book in sorted(r.json()[\"bookmakers\"].items()):\n    winner = book[\"markets\"].get(\"171\")\n    if not winner:\n        continue\n    for oid, outcome in sorted(winner[\"outcomes\"].items()):\n        snaps = outcome[\"players\"][\"0\"]\n        pre = [s for s in snaps\n               if dt.datetime.fromisoformat(s[\"createdAt\"].replace(\"Z\", \"+00:00\")) &lt; START\n               and s[\"active\"]]\n        if not pre:\n            continue\n        moves = sum(1 for a, b in zip(pre, pre[1:]) if a[\"price\"] != b[\"price\"])\n        print(f\"{slug:&lt;10} leg {oid}  open {pre[0]['price']:&lt;6} close {pre[-1]['price']:&lt;6} \"\n              f\"{len(pre):&gt;3} pre-match snapshots, {moves:&gt;2} price changes, \"\n              f\"limit {pre[-1]['limit']}\")<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>1xbet      leg 171  open 1.38   close 1.34    25 pre-match snapshots,  4 price changes, limit None\n1xbet      leg 172  open 3.145  close 3.36    25 pre-match snapshots,  7 price changes, limit None\npinnacle   leg 171  open 1.375  close 1.336   36 pre-match snapshots, 30 price changes, limit 6696.0\npinnacle   leg 172  open 3.11   close 3.34    36 pre-match snapshots, 31 price changes, limit 2250.0\nstake      leg 171  open 1.35   close 1.28    62 pre-match snapshots, 13 price changes, limit None\nstake      leg 172  open 2.9    close 3.3     62 pre-match snapshots, 13 price changes, limit None<\/code><\/pre>\n<p>Two things to read there. Pinnacle moved its favourite 30 times in eleven hours and closed at a 6,696 limit, while 1xBet moved four times. And Stake closed the favourite at 1.28 against Pinnacle&#8217;s 1.336, a 4.2% shorter price on the same match. Filter on <code>createdAt &lt; startTime<\/code>, because snapshots keep arriving after the series begins, and take the last <em>active<\/em> snapshot as the close. The <code>limit<\/code> field is populated by Pinnacle and the exchanges, so null-check it before any arithmetic. A season of this feeds straight into a <a href=\"https:\/\/oddspapi.io\/blog\/backtest-betting-model-free-historical-odds\/\">closing-line backtest<\/a>.<\/p>\n<h2>Where to Go Next<\/h2>\n<p>The same 28-market shape covers every Counter-Strike circuit on the feed, from PGL Masters down to a CCT Contenders qualifier with nine books. For Dota 2, League of Legends and Valorant, swap the <code>sportId<\/code> and re-read the catalogue, because each title carries its own ladder. Start with 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> for the cross-title view.<\/p>\n<p>If you need the board to push rather than poll, <code>\/v4<\/code> has a <a href=\"https:\/\/oddspapi.io\/blog\/websocket-odds-api-real-time-betting-data\/\">WebSocket feed<\/a> that streams price changes as the books make them. Polling a 155-book CS2 payload every few seconds burns requests you do not need to spend.<\/p>\n<h2>Start Pulling CS2 Odds<\/h2>\n<p>The catalogue held 357 bookmaker slugs on 10 September 2026, and 170 of them quoted at least one of the fourteen deep CS2 boards we measured. The free tier covers all of them, plus every historical snapshot, with no card and no sales call. <a href=\"https:\/\/oddspapi.io\/en\/sign-up\">Create a key<\/a>, run the first script in this post, and you will have the whole PGL slate in JSON inside a minute. The <a href=\"https:\/\/oddspapi.io\/blog\/free-odds-api-350-bookmakers\/\">free odds API guide<\/a> covers the rate limits and the endpoint list.<\/p>\n<h2>FAQ<\/h2>\n<h3>What is the market ID for the CS2 match winner?<\/h3>\n<p>Market <code>171<\/code>, named &#8220;Winner&#8221;, with outcome 171 for participant 1 and 172 for participant 2. On Fluxo v Dendele at PGL Masters Bucharest, 132 of the 134 books on the fixture quoted it with two active legs.<\/p>\n<h3>Why does one CS2 fixture return fifteen &#8220;Maps Handicap&#8221; markets?<\/h3>\n<p>Each rung of the ladder is its own market ID. IDs 1717 through 1745 cover -3.5 to +3.5 maps in 0.5 steps, and they all carry the same <code>marketName<\/code>. Read the <code>handicap<\/code> field from <code>\/v4\/markets<\/code> to tell them apart, and key your parser on the pair rather than the name.<\/p>\n<h3>How do I settle a CS2 map handicap bet?<\/h3>\n<p>Add the market&#8217;s <code>handicap<\/code> value to participant 1&#8217;s map margin. Positive settles as a win, negative as a loss, zero as a push. Checked against <code>\/v4\/settlements<\/code> on two played best-of-threes, that rule matched the feed on all fifteen rungs both times.<\/p>\n<h3>Which bookmakers price Counter-Strike 2 the tightest?<\/h3>\n<p>Across 14 deep boards measured on 10 September 2026, Polymarket ran a 1.00% median margin on the series winner, Kalshi 1.03% and Duel 3.49%, against a 6.46% board median over 63 books. Polymarket and Kalshi appeared on all 14 fixtures.<\/p>\n<h3>How much CS2 history can I pull on the free tier?<\/h3>\n<p>Every recorded snapshot. On one FISSURE Playground series, Pinnacle history opened eleven hours before the first map and held 36 pre-match active snapshots on the favourite with 30 price changes. Request up to three bookmakers per call.<\/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\": \"What is the market ID for the CS2 match winner?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Market 171, named Winner, with outcome 171 for participant 1 and 172 for participant 2. On Fluxo v Dendele at PGL Masters Bucharest, 132 of the 134 books on the fixture quoted it with two active legs.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why does one CS2 fixture return fifteen Maps Handicap markets?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Each rung of the ladder is its own market ID. IDs 1717 through 1745 cover -3.5 to +3.5 maps in 0.5 steps, and they all carry the same marketName. Read the handicap field from \/v4\/markets to tell them apart, and key your parser on the pair rather than the name.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How do I settle a CS2 map handicap bet?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Add the market's handicap value to participant 1's map margin. Positive settles as a win, negative as a loss, zero as a push. Checked against \/v4\/settlements on two played best-of-threes, that rule matched the feed on all fifteen rungs both times.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Which bookmakers price Counter-Strike 2 the tightest?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Across 14 deep boards measured on 10 September 2026, Polymarket ran a 1.00% median margin on the series winner, Kalshi 1.03% and Duel 3.49%, against a 6.46% board median over 63 books. Polymarket and Kalshi appeared on all 14 fixtures.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How much CS2 history can I pull on the free tier?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Every recorded snapshot. On one FISSURE Playground series, Pinnacle history opened eleven hours before the first map and held 36 pre-match active snapshots on the favourite with 30 price changes. Request up to three bookmakers per call.\"\n      }\n    }\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: cs2 odds api\nSEO Title: CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs\nMeta Description: A CS2 odds API call returns up to 155 bookmakers and 28 market IDs. The map handicap spans 15 of them, and \/settlements grades every rung on a played Bo3.\nSlug: cs2-odds-api\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A CS2 odds API call returns up to 155 bookmakers and 28 market IDs. The map handicap spans 15 of them, and \/settlements grades every rung on a played Bo3.<\/p>\n","protected":false},"author":2,"featured_media":3972,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[99,13,9,11,10],"class_list":["post-3971","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-cs2","tag-esports","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>CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs | 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\/cs2-odds-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"A CS2 odds API call returns up to 155 bookmakers and 28 market IDs. The map handicap spans 15 of them, and \/settlements grades every rung on a played Bo3.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-21T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"675\" \/>\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=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs\",\"datePublished\":\"2026-09-21T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/\"},\"wordCount\":1449,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp\",\"keywords\":[\"CS2\",\"Esports\",\"Odds API\",\"Python\",\"Sports Betting API\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/\",\"name\":\"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp\",\"datePublished\":\"2026-09-21T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp\",\"width\":1200,\"height\":675,\"caption\":\"CS2 Odds API header\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs\"}]},{\"@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":"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs | 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\/cs2-odds-api\/","og_locale":"en_US","og_type":"article","og_title":"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs | OddsPapi Blog","og_description":"A CS2 odds API call returns up to 155 bookmakers and 28 market IDs. The map handicap spans 15 of them, and \/settlements grades every rung on a played Bo3.","og_url":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-09-21T10:00:00+00:00","og_image":[{"width":1200,"height":675,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.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":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs","datePublished":"2026-09-21T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/"},"wordCount":1449,"commentCount":1,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp","keywords":["CS2","Esports","Odds API","Python","Sports Betting API"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/","url":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/","name":"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp","datePublished":"2026-09-21T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/cs2-odds-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/cs2-odds-api.webp","width":1200,"height":675,"caption":"CS2 Odds API header"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/cs2-odds-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"CS2 Odds API: Resolve the Map Handicap Across 15 Market IDs"}]},{"@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\/3971","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=3971"}],"version-history":[{"count":1,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3971\/revisions"}],"predecessor-version":[{"id":3973,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3971\/revisions\/3973"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/3972"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=3971"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=3971"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=3971"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}