Polymarket Sports Odds API & +EV Edge Finder
Pricing
from $1.00 / 1,000 market rows
Polymarket Sports Odds API & +EV Edge Finder
Live Polymarket sports odds as JSON (NFL, MLB, NBA, NHL, soccer, UFC, esports): price, bid/ask, volume, teams, start time. Games-only and next-48h filters, no key needed. Add a free The Odds API key for +EV edges vs Pinnacle no-vig lines with Kelly size.
Pricing
from $1.00 / 1,000 market rows
Rating
0.0
(0)
Developer
Jack Sheward
Maintained by CommunityActor stats
1
Bookmarked
16
Total users
0
Monthly active users
11 days ago
Last modified
Categories
Share
Polymarket Sports Odds Scanner & Divergence Finder
Pull live Polymarket sports odds as clean JSON. Polymarket lists 8,000+ live sports events and 150,000+ open markets (counted 2026-09-24): soccer, NFL, MLB, NBA, NHL, UFC, tennis, cricket, esports and more. Each run returns up to 2,000 of them, filtered by sport, games only, start time or text. Game rows carry the league, the home and away teams and the start time. Every row with an order book carries its top: bid, ask, spread, last trade, 24h volume and 24h price change. Futures leave the team fields null, and often the start time and league too.
Optionally, the actor also surfaces divergence between Polymarket prices and sharp sportsbook lines (Pinnacle by default) using your own The Odds API key. Each signal gives the no-vig fair probability, the edge in percentage points, which side to buy and a quarter-Kelly stake size.
Polymarket data comes straight from the public, unauthenticated Gamma API — no login, no scraping. Sportsbook lines come from The Odds API with a buyer-supplied key. The free tier (500 credits/month) covers daily runs: this actor makes one odds call per active matching league per run, never one per market.
Quick start
Today's games, soonest first (no key needed):
{ "mode": "scan", "scope": "games", "hoursAhead": 48, "maxMarkets": 100 }
One league, compact rows for an AI agent:
{ "sports": ["mlb"], "scope": "games", "hoursAhead": 24, "maxMarkets": 30, "compactOutput": true }
Only the edges against Pinnacle (bring your own The Odds API key):
{ "signalsOnly": true, "oddsApiKey": "YOUR-ODDS-API-KEY", "scope": "games", "hoursAhead": 48, "minEdgePct": 3 }
What you get
scan mode — one market record per Polymarket sports market
| Field | Example | Notes |
|---|---|---|
record_type | market | |
market_id | 4685259 | Gamma market id |
condition_id | 0xb3e62… | on-chain condition id |
title | Houston Astros vs. Athletics | market question |
sport | mlb | canonical sport (see Sports); null when the sport is not one of them (darts, table tennis, rugby, college football…) |
teams | ["Houston Astros", "Athletics"] | best-effort, in title order; null for outrights/props. Use home_team/away_team for sides |
event_date | 2026-09-25T01:40:00Z | game start when known, else market end date |
yes_price | 0.625 | price of outcome 0 (USD, 0–1) |
no_price | 0.375 | price of outcome 1 |
outcome_labels | ["Houston Astros", "Athletics"] | ["Yes", "No"] or team names |
volume | 76921.57 | USD total traded |
liquidity | 479475.05 | USD posted liquidity |
outcome_token_ids | ["855249…", "808415…"] | CLOB token ids, index-aligned with outcome_labels |
url | https://polymarket.com/event/mlb-hou-oak-2026-09-24 | event page |
market_type | moneyline | Polymarket's type for game markets: moneyline, spreads, totals, team_totals, props…; null for futures |
league | mlb | Polymarket league code: nfl, mlb, epl, kbo, npb, atp, cs2, cfb…; null when unknown. The same codes work as filters in sports |
game_start_time | 2026-09-25T01:40:00Z | scheduled game start. Some futures carry their season's start instead (MLB win totals: 2026-03-25T17:00:00Z); null when Polymarket gives none |
home_team / away_team | Athletics / Houston Astros | from Polymarket's team data; null when not a two-sided game |
best_bid / best_ask | 0.62 / 0.63 | order-book top for outcome 0 (the YES / first-listed side). best_bid is 0 when the book has asks but no bids |
spread | 0.01 | best ask − best bid |
last_trade_price | 0.63 | last fill, outcome 0; null if it never traded |
volume_24h | 76826.20 | USD traded in the last 24 h (0 = none) |
price_change_24h | 0.02 | outcome-0 price change over 24 h (0 = unchanged) |
Real market record (MLB moneyline, local run 2026-09-24):
{"record_type": "market","market_id": "4685259","condition_id": "0xb3e62cd9ca1025cc820f37f20a9e422e9a0b5894ed4a06fc6c1b7ab51a950281","title": "Houston Astros vs. Athletics","sport": "mlb","teams": ["Houston Astros", "Athletics"],"event_date": "2026-09-25T01:40:00Z","yes_price": 0.625,"no_price": 0.375,"outcome_labels": ["Houston Astros", "Athletics"],"volume": 76921.56803899999,"liquidity": 479475.0461,"outcome_token_ids": ["85524905959057263956879322517417832399581005109501374226420581643283253844799","80841557773416442931766539440604863817140415173966155507548464389339180861877"],"url": "https://polymarket.com/event/mlb-hou-oak-2026-09-24","market_type": "moneyline","league": "mlb","game_start_time": "2026-09-25T01:40:00Z","home_team": "Athletics","away_team": "Houston Astros","best_bid": 0.62,"best_ask": 0.63,"spread": 0.01,"last_trade_price": 0.63,"volume_24h": 76826.198039,"price_change_24h": 0.02}
Polymarket leaves zero values out of its feed, so a missing bid, 24 h volume or 24 h price change is reported as 0. These book fields are null only for a market with no order-book data at all.
With compactOutput: true the same row drops condition_id, outcome_token_ids, outcome_labels and every null field. It measured about 40% smaller (964 → 565 bytes on average on 2026-09-24) at the same price.
divergence mode — everything above plus one signal record per matched market × book with edge ≥ minEdgePct
Signal records repeat all market fields and add:
| Field | Example | Notes |
|---|---|---|
record_type | signal | |
book | pinnacle | bookmaker key |
book_odds_decimal | 3.40 | the book's decimal odds for the YES side's outcome |
implied_prob_novig | 0.2846 | fair probability after removing the book's vig |
polymarket_prob | 0.445 | Polymarket YES price. For buy_no signals the actionable price is no_price (same record) |
edge_pct | 16.04 | fair prob of the recommended side minus its Polymarket price, ×100 |
direction | buy_no | buy_yes or buy_no |
kelly_fraction_25 | 0.0901 | quarter-Kelly fraction of bankroll for that side |
match_confidence | high | high (exact team match) or medium (conservative fuzzy match) |
matched_event | New England Revolution vs Houston Dynamo | the sportsbook event it matched |
commence_time | 2026-08-08T20:30:00Z | game start per the book |
Example signal record (unit-test fixture; some market fields are left out for brevity):
{"record_type": "signal","market_id": "1356220","title": "Will New England Revolution vs. Houston Dynamo end in a draw?","sport": "soccer","league": "mls","teams": ["New England Revolution", "Houston Dynamo"],"event_date": "2026-08-08T20:30:00Z","yes_price": 0.445,"no_price": 0.555,"url": "https://polymarket.com/event/mls-ner-hou-2026-03-07","book": "pinnacle","book_odds_decimal": 3.40,"implied_prob_novig": 0.2846,"polymarket_prob": 0.445,"edge_pct": 16.04,"direction": "buy_no","kelly_fraction_25": 0.0901,"match_confidence": "high","matched_event": "New England Revolution vs Houston Dynamo","commence_time": "2026-08-08T20:30:00Z"}
The dataset has three table views: Markets (prices, book and timing columns), Divergence signals (edge, side, Kelly, book) and the original Overview. Export as JSON, CSV or Excel directly from the dataset.
Input
| Input | Default | What it does |
|---|---|---|
mode | scan | scan (Polymarket markets only) or divergence (scan + sportsbook comparison) |
scope | all | games = individual games only (moneyline, spreads, totals, props); all also includes futures and outrights |
sports | ["all"] | sports and/or single leagues to keep (see below) |
hoursAhead | 0 (off) | only events that have not started and start within this many hours, soonest first (max 336). Events without a start time (most futures) drop out. A race or tournament outright that starts inside the window (e.g. an F1 Grand Prix winner market) stays unless scope is games |
query | — | text filter on question, event title, teams and league. "lakers celtics" = both words, "yankees, dodgers" = either. Terms match from the start of a word (yank finds Yankees; nets does not match Hornets). Case- and accent-insensitive |
minVolume / minLiquidity | 0 | USD floors; 0 disables |
maxMarkets | 200 | 1–2000 cap on market rows, counted after every filter |
compactOutput | false | smaller rows (see above) |
oddsApiKey | — | your The Odds API key, needed only for divergence. Used solely for this run's requests: never stored, never logged. A missing key gives a warning plus scan output |
signalsOnly | false | return only signals: market rows are scanned for matching but not saved or charged. Turns on divergence mode. Needs oddsApiKey; without it the run stops at once with one free explanatory row and charges nothing |
books | ["pinnacle"] | The Odds API bookmaker keys (Pinnacle is the sharp baseline). An empty list also means Pinnacle. ["all"] compares every bookmaker in regions instead: one signal (and one divergence-signal charge) per market per book, often 20–40× the signals |
minEdgePct | 3 | signal floor in percentage points |
regions | us,eu | The Odds API regions. Only used when books is ["all"]: when you name bookmakers, The Odds API ignores regions, and the run logs a warning if you changed it. Each region costs 1 credit per odds call |
Filters run while the actor pages through Polymarket, so maxMarkets counts matching rows only. Sport and league filters and scope: "games" are also sent to Polymarket as tag filters, so a one-sport run reads that sport's pages rather than the whole catalog. A soccer league reads just its own pages. Other leagues read their sport's pages and keep the league's rows, because some of their matches (all ATP and WTA ones, for example) are tagged only with the sport.
Sports
nba, wnba, nfl, mlb and nhl are the US major leagues. basketball, baseball and hockey label every other league of those sports (EuroLeague, KBO, NPB, KHL and so on). The other names are ufc, boxing, soccer, tennis, cricket, f1, golf and esports. "all" also keeps markets with sport: null.
As a filter, a sport word means the whole sport: basketball = NBA + WNBA + every other league, baseball = MLB + KBO + NPB + …, hockey = NHL + the rest. football is ambiguous and scans both nfl and soccer.
A league name keeps just that league (matched on the row's league): epl, ucl, uel, lal (La Liga), bun (Bundesliga), sea (Serie A), fl1 (Ligue 1), mls, fifwc, kbo, npb, cpbl, khl, shl, ahl, euroleague, cbb, ncaab, cfb (college football), atp, wta, ipl, cs2, lol, val and dota2. Mix freely: ["mlb", "kbo"] = MLB + KBO. Filters are case-insensitive and accept full names such as premier league, champions league, la liga, college football, mma or formula 1.
How divergence detection works
- Scan active Polymarket sports markets (Gamma API, stale and non-trading markets filtered out at the market level). In divergence mode with an
oddsApiKeythe scan reads not-yet-started games soonest-first, so themaxMarketsbudget goes to games sportsbooks price pre-match (in-play games are skipped: Gamma prices lag live lines). - Classify each market's sport and league from Polymarket's league data and tags, falling back to a two-pass keyword/team-name classifier carried over from a production sports trading system.
- Match conservatively: only game-level moneyline markets with two parsed team names; team names are normalized (case, accents, punctuation, common aliases like "Man City") and both home/away orientations are checked; game time must agree within 12 hours. Anything below medium confidence is dropped, not guessed.
- De-vig the book's h2h line: implied probabilities
1/oddsare normalized over all outcomes (including Draw for soccer), sop(team)is the true win probability with draws counting against — exactly the YES side of Polymarket's "Will X win?" game markets. - Score:
edge_pct = (fair probability of side − Polymarket price of side) × 100; the better ofbuy_yes/buy_nois emitted when it clearsminEdgePct, with quarter-Kelly sizing0.25 × (p − price) / (1 − price).
Pricing
Pay per result, no subscription:
| Event | Price |
|---|---|
Run start (actor-start) | $0.005 |
Market row (market-row) | $0.001 |
Divergence signal (divergence-signal) | $0.02 |
| Example run | Rows | Cost |
|---|---|---|
AI agent: 30 games, compactOutput | 30 markets | $0.035 |
Next 48 h of games (scope: games, hoursAhead: 48, 100 markets) | 100 markets | $0.105 |
| Default scan | 200 markets | $0.205 |
| Divergence, 200 markets, 10 signals | 200 + 10 | $0.405 |
signalsOnly, 10 signals | 10 signals | $0.205 |
signalsOnly, no edge found | 1 free notice row | $0.005 |
signalsOnly without a key, or with a key The Odds API rejects | 1 free notice row | $0 |
| Maximum scan | 2,000 markets | $2.005 |
Divergence runs also use your own (free-tier) Odds API credits: one per active matching league, typically 1–15 per run. Soccer alone spans up to 8 leagues, and tennis and cricket use one per live tournament. Free explanatory notice rows are never charged.
FAQ
How do I get today's games only?
Set scope to games and hoursAhead to 24 or 48. You get markets of games that have not started yet, soonest first. Add sports (e.g. ["nfl"]) to stay in one league, because a single NFL game alone has 300+ markets (props, spreads, totals).
Why is hoursAhead based on start time, not the market end date?
About a fifth of Polymarket game events (tennis, KBO/NPB, cricket, CS2, table tennis) carry an end date one week after the game starts. An end-date window would silently drop them, so the actor filters on the scheduled start (checked 2026-09-24).
How do I find arbitrage between Polymarket and sportsbooks?
Run divergence mode (or signalsOnly) with your The Odds API key. Each signal tells you which side of the Polymarket market is cheap relative to the sharp no-vig line (direction), by how much (edge_pct), and a conservative stake size (kelly_fraction_25). True risk-free arbitrage also needs a hedge on the other side at the book. These signals are value signals against the sharp line.
What is no-vig (fair) probability?
Bookmaker odds embed a margin (vig): implied probabilities sum to more than 1. Dividing each implied probability by that sum removes the margin. Pinnacle's no-vig line is a widely used proxy for true probability.
Do I need an API key?
Not for scan mode, because Polymarket's Gamma API is public. For divergence mode you supply your own The Odds API key. The free tier (500 credits/month) is plenty for daily runs, because this actor makes one odds call per active matching league (never per market). A books list of up to 10 bookmakers, such as Pinnacle only, costs 1 credit per call.
How are Polymarket markets matched to sportsbook games?
By normalized team names (both orientations — Polymarket titles don't guarantee home team first) plus a ±12 h game-time window. Exact name matches are high confidence; token-subset/nickname matches are medium. Anything weaker is dropped rather than guessed.
How does it handle soccer's three-way (draw) odds?
The fair probability is computed over all three outcomes, so a team's implied_prob_novig already counts draws against it — directly comparable to Polymarket's binary "Will X win?" markets. Draw markets themselves match the book's Draw outcome. Double-chance or "to advance/qualify" markets are excluded from matching entirely.
Which sports are supported?
Scan covers everything under Polymarket's Sports tag. Divergence covers nba, wnba, nfl, mlb, nhl, ufc, boxing, soccer (top leagues + World Cup), tennis and cricket. Golf, F1, esports and the non-US basketball, baseball and hockey leagues have no h2h matching here.
Is my Odds API key stored anywhere?
No. It is used for this run's HTTP requests only — never written to the dataset, key-value store, or logs (HTTP client URL logging is explicitly disabled, and error messages are scrubbed).
Is this financial advice?
No. It is market data plus arithmetic. Prediction markets and sports betting carry real risk; sizing outputs are informational.
Limitations
- Matching is conservative by design. Markets that can't be matched at medium-or-better confidence produce no signal at all. Expect coverage, not completeness.
- Gamma prices can lag the live order book. Responses are CDN-cached for up to 5 minutes, and
yes_priceis the Gamma outcome price, not the live CLOB top of book.best_bid/best_askcome from the same cached response. Always check the live book before trading;outcome_token_idsare included so you can query the CLOB directly. - Divergence covers game-level moneyline markets only. It skips totals, spreads, props and outright/futures markets.
liquidityis total deposited liquidity, not depth at the current price — don't size positions off it.- The Odds API stops listing games near/after start; Polymarket may still show them. Postponed games can mismatch on date.
event_datefalls back to the market end date when Gamma omitsgameStartTime. Rescheduled games can then fall outside the ±12 h match window, which means missed signals, never false matches.- A run reads at most 30 Polymarket pages (~3,000 of the ~11,000 listed events). A text
queryor a volume floor with nosports/scope/hoursAheadcan hit that cap beforemaxMarketsfill; the run then says so in its log. Add a sport orscope: "games"to narrow the crawl. - Futures and outrights without Polymarket league data get their
sportfrom tags and a text classifier. Rare cross-sport team-name clashes can mislabel one. - A sport filter reads the events Polymarket files under that league. A few loosely related novelty markets have no league tag, such as "Will the Seattle Seahawks visit the White House in 2026?". An unfiltered scan labels them by text (
sport: nfl), but asports: ["nfl"]run does not reach them. Usequery(e.g."seahawks") to find them. - The buyer's The Odds API key is required for divergence mode. Without it, or if a pasted secret cannot be decrypted, the run still succeeds and ships the same records as scan mode (with
signalsOnly, one free notice row instead). - Games that started more than 12 hours ago are skipped: Polymarket keeps some finished games open for trading for months, and those prices are not live odds. Futures (season win totals, league winners) stay in until their end date passes.
- Transient Polymarket/Odds API errors are retried with backoff. If Polymarket's API stays unreachable the run fails with a clear status message and nothing is charged; an outage part-way through keeps the markets already scanned.
- Not financial advice.
Use with AI agents (MCP)
Connect your agent to the Apify MCP server (mcp.apify.com) and it can call this actor as a tool. Ask for "tonight's NBA games on Polymarket" or "find divergence vs Pinnacle above 5% in MLB" and the agent fills the input schema itself (mode, sports, scope, hoursAhead, query, minEdgePct). For agents, set compactOutput: true and maxMarkets to 20–50: rows are about 40% smaller and a run costs a few cents. signalsOnly: true returns just the actionable edges. Pair the scan output with the CLOB token ids for execution research.
More prediction-market data actors
- Kalshi Weather Markets Data — KXHIGH & KXLOW - live brackets and settlement history for Kalshi temperature markets.
- METAR & NWS Weather Station Observations API - the raw station observations weather markets settle on.
- Prediction Market Resolution Evidence Checker - paste a market URL, get the live observation that resolves it, graded.
Changelog
2026-09-25
- Billing fix, pagination: this build pages with
after_cursorand dedupes events and markets across pages. A page that repeats earlier event ids, or a cursor that repeats, now stops the crawl. An earlier deployed build could re-read page 1 and bill repeated rows (2,000 billed, 771 unique in one audit). A local 2,000-market run on 2026-09-24 returned 2,000 rows with 2,000 unique market ids. - New inputs:
scope(games only),hoursAhead(games starting soon, soonest first),query(text filter; terms match at word starts, sonetsfinds the Nets but not the Hornets),compactOutput,signalsOnly(free when there is no key or The Odds API rejects it). Sport and league filters andscopeare now sent to Polymarket as tag filters, so a one-sport run reads that sport's pages instead of the whole catalog. A run whosehoursAhead/scope/sportswindow holds no events says which filter to widen. - New fields (existing fields unchanged):
market_type,league,game_start_time,home_team,away_team,best_bid,best_ask,spread,last_trade_price,volume_24h,price_change_24h. - League filters:
sportsaccepts single leagues (epl,ucl,kbo,npb,atp,wta,cs2,cfb…) and keeps only that league. Behaviour change: league words used to mean their whole sport (epl,premier league,serie a,atp,wta,ipl,cs2,lol,valorant… returned all soccer, tennis, cricket or esports), andkbowas not recognised at all (it logged a warning and scanned every sport). A league that is out of season (IPL in September) now returns no rows, and the status message suggests the sport word, e.g.sports: ["cricket"]. - Sport labels fixed: KBO, NPB and CPBL games were labelled
mlb, other basketball leaguesnba, and KHL, SHL and other hockey leaguesnhl. They now reportbaseball,basketballorhockey, with the league inleague. Table tennis is no longertennis, darts no longerf1, and rugby, CFL and AFL no longernfl/soccer(these now havesport: null). College-football futures ("Will Oregon Ducks win the CFP?") were read asnhl,nfl,mlbornbafrom team nicknames and now havesport: null,league: cfb. sports: ["nfl"]also reads Polymarket's Super Bowl tag (halftime-show and similar NFL markets). Book fields that Polymarket omits when zero (bid, 24 h volume, 24 h price change) are reported as0.regionsnow logs a warning when it is set but ignored (you named bookmakers). Divergence settings are grouped in their own section. There are new Markets and Divergence signals dataset views.