Polymarket Sports Odds API & +EV Edge Finder avatar

Polymarket Sports Odds API & +EV Edge Finder

Pricing

from $1.00 / 1,000 market rows

Go to Apify Store
Polymarket Sports Odds API & +EV Edge Finder

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

Jack Sheward

Maintained by Community

Actor stats

1

Bookmarked

16

Total users

0

Monthly active users

11 days ago

Last modified

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

FieldExampleNotes
record_typemarket
market_id4685259Gamma market id
condition_id0xb3e62…on-chain condition id
titleHouston Astros vs. Athleticsmarket question
sportmlbcanonical 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_date2026-09-25T01:40:00Zgame start when known, else market end date
yes_price0.625price of outcome 0 (USD, 0–1)
no_price0.375price of outcome 1
outcome_labels["Houston Astros", "Athletics"]["Yes", "No"] or team names
volume76921.57USD total traded
liquidity479475.05USD posted liquidity
outcome_token_ids["855249…", "808415…"]CLOB token ids, index-aligned with outcome_labels
urlhttps://polymarket.com/event/mlb-hou-oak-2026-09-24event page
market_typemoneylinePolymarket's type for game markets: moneyline, spreads, totals, team_totals, props…; null for futures
leaguemlbPolymarket league code: nfl, mlb, epl, kbo, npb, atp, cs2, cfb…; null when unknown. The same codes work as filters in sports
game_start_time2026-09-25T01:40:00Zscheduled 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_teamAthletics / Houston Astrosfrom Polymarket's team data; null when not a two-sided game
best_bid / best_ask0.62 / 0.63order-book top for outcome 0 (the YES / first-listed side). best_bid is 0 when the book has asks but no bids
spread0.01best ask − best bid
last_trade_price0.63last fill, outcome 0; null if it never traded
volume_24h76826.20USD traded in the last 24 h (0 = none)
price_change_24h0.02outcome-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:

FieldExampleNotes
record_typesignal
bookpinnaclebookmaker key
book_odds_decimal3.40the book's decimal odds for the YES side's outcome
implied_prob_novig0.2846fair probability after removing the book's vig
polymarket_prob0.445Polymarket YES price. For buy_no signals the actionable price is no_price (same record)
edge_pct16.04fair prob of the recommended side minus its Polymarket price, ×100
directionbuy_nobuy_yes or buy_no
kelly_fraction_250.0901quarter-Kelly fraction of bankroll for that side
match_confidencehighhigh (exact team match) or medium (conservative fuzzy match)
matched_eventNew England Revolution vs Houston Dynamothe sportsbook event it matched
commence_time2026-08-08T20:30:00Zgame 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

InputDefaultWhat it does
modescanscan (Polymarket markets only) or divergence (scan + sportsbook comparison)
scopeallgames = individual games only (moneyline, spreads, totals, props); all also includes futures and outrights
sports["all"]sports and/or single leagues to keep (see below)
hoursAhead0 (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 / minLiquidity0USD floors; 0 disables
maxMarkets2001–2000 cap on market rows, counted after every filter
compactOutputfalsesmaller 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
signalsOnlyfalsereturn 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
minEdgePct3signal floor in percentage points
regionsus,euThe 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

  1. Scan active Polymarket sports markets (Gamma API, stale and non-trading markets filtered out at the market level). In divergence mode with an oddsApiKey the scan reads not-yet-started games soonest-first, so the maxMarkets budget goes to games sportsbooks price pre-match (in-play games are skipped: Gamma prices lag live lines).
  2. 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.
  3. 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.
  4. De-vig the book's h2h line: implied probabilities 1/odds are normalized over all outcomes (including Draw for soccer), so p(team) is the true win probability with draws counting against — exactly the YES side of Polymarket's "Will X win?" game markets.
  5. Score: edge_pct = (fair probability of side − Polymarket price of side) × 100; the better of buy_yes/buy_no is emitted when it clears minEdgePct, with quarter-Kelly sizing 0.25 × (p − price) / (1 − price).

Pricing

Pay per result, no subscription:

EventPrice
Run start (actor-start)$0.005
Market row (market-row)$0.001
Divergence signal (divergence-signal)$0.02
Example runRowsCost
AI agent: 30 games, compactOutput30 markets$0.035
Next 48 h of games (scope: games, hoursAhead: 48, 100 markets)100 markets$0.105
Default scan200 markets$0.205
Divergence, 200 markets, 10 signals200 + 10$0.405
signalsOnly, 10 signals10 signals$0.205
signalsOnly, no edge found1 free notice row$0.005
signalsOnly without a key, or with a key The Odds API rejects1 free notice row$0
Maximum scan2,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_price is the Gamma outcome price, not the live CLOB top of book. best_bid/best_ask come from the same cached response. Always check the live book before trading; outcome_token_ids are included so you can query the CLOB directly.
  • Divergence covers game-level moneyline markets only. It skips totals, spreads, props and outright/futures markets.
  • liquidity is 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_date falls back to the market end date when Gamma omits gameStartTime. 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 query or a volume floor with no sports/scope/hoursAhead can hit that cap before maxMarkets fill; the run then says so in its log. Add a sport or scope: "games" to narrow the crawl.
  • Futures and outrights without Polymarket league data get their sport from 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 a sports: ["nfl"] run does not reach them. Use query (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

Changelog

2026-09-25

  • Billing fix, pagination: this build pages with after_cursor and 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, so nets finds the Nets but not the Hornets), compactOutput, signalsOnly (free when there is no key or The Odds API rejects it). Sport and league filters and scope are now sent to Polymarket as tag filters, so a one-sport run reads that sport's pages instead of the whole catalog. A run whose hoursAhead/scope/sports window 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: sports accepts 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), and kbo was 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 leagues nba, and KHL, SHL and other hockey leagues nhl. They now report baseball, basketball or hockey, with the league in league. Table tennis is no longer tennis, darts no longer f1, and rugby, CFL and AFL no longer nfl/soccer (these now have sport: null). College-football futures ("Will Oregon Ducks win the CFP?") were read as nhl, nfl, mlb or nba from team nicknames and now have sport: 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 as 0.
  • regions now 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.