Skip to main content
These are the API changelog entries from November 4, 2026, newest first. The newest changes are on the API changelog.
Each market's closing line, and closing line value on every large trade and per wallet
GET /api/v1/market/{condition_id}/close is new. It returns a sports or esports market’s closing price on each side, read from Polymarket’s price history in the last minute before kickoff, with the interval and source it came from. A market without one says pending or unavailable with a reason, never 0.Every large trade now carries clv, its closing line value against that close, on GET /api/v1/large-trades, /large-trades/history, /large-trades/{id}, and the trades on /events/feed/since:
  • status: measured, in_play (placed at or after kickoff), pending (the close is not stored yet), or unavailable, with unavailable_reason.
  • clv_cents: positive when the trade beat the close. On a buy it is the closing price minus the price paid, on a sell the price received minus the closing price, in cents per share and before fees.
  • close_price, close_anchor_at, pre_kickoff, and basis_version (clv@v1).
GET /api/v1/trader/{address}/clv is new. It sums a wallet’s large trades in a window: average CLV, size-weighted average, the share that beat the close, and a per-market average with a 95% interval.The remote MCP server adds the tools get_market_close and get_trader_clv. The stdio MCP server, the CLI (market close, traders clv) and the TypeScript client (getMarketClose, getTraderClv) add them in their next release. Both endpoints need a Pro or Max key.Backward compatible. clv is a new field on the large trade object; no field changed.What to change: Nothing. If your client refuses unknown fields on a large trade, allow clv.
SDK 0.40.0 and MCP 3.14.0 carry game market settlement, quotes and trading terms
@0xinsider/sdk 0.40.0 and @0xinsider/mcp 3.14.0 are on npm, and 3.14.0 is in the MCP Registry. They bring the November 4 game market changes listed below to the SDK types, the local MCP server and the CLI.Before these releases, the local list_game_markets tool in 3.13.0 accepted only "sharp_money" in expand and refused "quotes" and "trading_terms" with an input validation error. SDK 0.39.0 had no type for settlement, quote or trading_terms. The entries below said the MCP tool and the SDK types describe these fields, which was true of the remote MCP server and not yet of the packages you install.
  • SDK: every listGameMarkets row carries settlement, expand: ["quotes"] adds each outcome’s quote, and expand: ["trading_terms"] adds each row’s trading_terms, with min_order_size_shares.
  • SDK: getMarketSnapshot and the getGame winner markets carry settlement, and listGames takes expand: ["settlement"].
  • Local MCP: list_game_markets takes "quotes" and "trading_terms" in expand, and list_games takes expand as one value or an array of "sharp_money" and "settlement". The list_game_markets, list_games, get_game and get_market_snapshot descriptions match the remote server’s.
  • Both: the league description says to spell a league as the list’s own coverage.leagues does, since GET /api/v1/coverage lists no leagues.
The local server lists the same 69 tools as the remote server. The CLI, MCP and introduction pages now install @0xinsider/mcp@3.14.0.Backward compatible. Every change adds a type, a field or an expand value, and one list_games expand value still works.What to change: Run npm install @0xinsider/sdk@0.40.0. For the CLI and the local MCP server, run npm install --global @0xinsider/mcp@3.14.0, or change a client’s @0xinsider/mcp@3.13.0 argument to @0xinsider/mcp@3.14.0. 0xinsider --version prints 3.14.0 once the update is in place.
A team keeps one name before, during and after its game, the name its moneyline outcome uses
GET /api/v1/games and GET /api/v1/games/{event_slug}, and the MCP list_games and get_game tools, now give a team the same competitors[].name in every state: upcoming, live and finished. It is the moneyline outcome that names the team, in the outcome’s own text, so a side reads as the label Polymarket prices it under.Before this change, the name depended on the game’s state. Over every upcoming and live game and every game finished since October 28, read on November 4, 573 teams in 43 leagues carried more than one name; with this change, none do. An upcoming NFL game read Jacksonville Jaguars while its moneyline, and the same team’s finished games, read Jaguars. A finished Premier League game read Villa while upcoming ones read Aston Villa FC.
  • NFL upcoming games: the nickname the outcomes use (Jaguars, Ravens). NHL: Utah, not Mammoth.
  • Tennis, every state: the full name the outcome uses (Jacopo Vasami, not J. Vasami).
  • MLB and other finished games: the outcome’s name (Milwaukee Brewers, not Brewers).
  • Soccer, whose win markets read Yes and No: the club’s full name in every state (Aston Villa FC).
  • Where Polymarket’s outcome drops an accent, so does the name (Fenerbahce). Where an outcome names a team some other way (Canada for Team Canada), the team’s full name stays.
  • Upcoming games’ markets[].outcome_yes and outcome_no carry the same text.
  • provider_id, logo, side and price values are unchanged. No team lost a provider_id or a paired price.
Backward compatible. No field was added, removed or retyped. Only competitors[].name values changed, and upcoming games’ outcome labels with them.What to change: A client that matched a team by its old name should match by provider_id, which is the same in every state, or by the name now served.
Game markets carry each market's minimum order size in shares on expand=trading_terms
GET /api/v1/games/{event_slug}/markets with expand=trading_terms now carries trading_terms.min_order_size_shares: the smallest order Polymarket’s order book accepts for the market, in shares. It is Polymarket’s orderMinSize, read from the same market record as the other terms.Before this change, trading_terms left the minimum order size out. Polymarket’s market reference calls the figure USDC and its order guide calls it shares. Polymarket’s order book accepts a limit order of exactly that many shares at the smallest price step, worth as little as $0.05, so the unit is shares.
  • min_order_size_shares: a number, or null when the record carries none or status is not observed. It was 5 on every open sports market we read on November 4.
  • Compare it with an order’s share count, not its dollar cost. A buy of 5 shares at $0.40 costs $2.00 and meets a minimum of 5.
  • The list_game_markets MCP tool, the SDK types and the OpenAPI document describe the same.
Backward compatible. The field is new; no field was removed or retyped.What to change: Nothing. To check an order against the minimum, read min_order_size_shares instead of a separate order book request.
Finished soccer games name the home and away side of each team-win market
A finished soccer game in GET /api/v1/games/{event_slug} and GET /api/v1/games now sends side home or away on its two team-win markets after it leaves the live board, as it did before kickoff. The draw market keeps side draw.Before this change, those two markets left out side, so only the market slug told a client which team each one priced. On November 4, 2026 that was 2,130 markets of the 1,065 finished soccer games since October 28.
  • The team is the one Polymarket’s own title for the market names, such as FC Bayern München, matched to one of the game’s two competitors. The first competitor is home, the second away.
  • side is still left out when the game’s markets store no team pair, when the title names neither competitor or both, when both markets name the same team, or when the market’s slug names the other team. It is never taken from the slug or from the order of the markets.
  • Other sports, and soccer games still on the live board, are unchanged.
Backward compatible. side was already documented on these markets and is now sent where it was missing.What to change: Nothing. If you read a finished soccer market’s team from its slug, read side instead.
Quotes and snapshots no longer serve a 0 bid or a 1 ask for a side with no orders
GET /api/v1/games/{event_slug}/markets with expand=quotes and GET /api/v1/market/{condition_id}/snapshot now serve a book with one side, or with no orders, as that book for as long as we stream it, also after its side moves, flips or empties.Polymarket’s best bid and ask stream sends a side with no orders as a bid of 0 or an ask of 1. Before this change, we stored that as a price. Such a book read as two-sided, then as missing:
  • Its quote carried best_bid: 0 or best_ask: 1, and its snapshot read top_of_book.status: available. On November 4 at 11:27 UTC, the junjilopzfx0764 vs. Stronghold Overwatch moneyline (ow-jun-strong-2026-11-04) served junjilopzfx0764 at bid 0 / ask 0.97 and Stronghold at bid 0.03 / ask 1, while Polymarket’s book held only asks for the first and only bids for the second.
  • Once that book went 30 seconds without an update, the outcome read unavailable (cache_miss on the snapshot). The same market read cache_miss from 11:37 to 11:42 UTC while its Polymarket book stayed the same.
Now:
  • A served best_bid is never 0 and a served best_ask is never 1. A side with no orders is null beside a set book_observed_at, and the outcome stays observed while its book has one side or none.
  • The snapshot reads one_sided_book or empty_book for such a book, never available.
  • Books with orders on both sides are unchanged.
Backward compatible. No field was added, removed or retyped; only values change.What to change: Nothing. A client that treated a 0 bid or a 1 ask as a price can drop that handling.
Finished games that store no team pair show each side's crest, and its provider_id where it has one
A finished game in GET /api/v1/games/{event_slug} and GET /api/v1/games whose markets store no pair of team ids now matches each side to one of the two teams its slug names. Each matched side carries that team’s logo, and its provider_id where the team has one. Most of these are FCS college football games: Polymarket has no team id for many of those schools.Before this change, such a game served each side’s name with no provider_id and no logo:
  • Bryant vs. Brown on October 10 (cfb-bryant-brwn-2026-10-10) served neither side’s id or logo, though Bryant’s id is 231.
  • 63 finished college football games played since October 5 were affected. Of their 126 sides, 30 carried an id and 86 a logo.
Each of these games now serves its two teams:
  • How a side is matched: by its outcome name, such as Brown, against the two teams the slug’s codes name (bryant, brwn), exactly or by its words, never by position. When a stored final score names neither side’s team, the settled moneyline decides: the side with the higher score is the team the winning outcome names.
  • logo is the team’s crest. provider_id is the team’s id, or absent when the team has none. In the 63 games, 44 sides now carry an id and 125 a logo.
  • coverage.competitors is provider_ids only when both sides carry an id, else labels. One Counter-Strike game, maybe vs. Honvéd on November 2, now reads provider_ids.
  • Games whose markets store a team pair are unchanged.
Backward compatible. No field was added, removed or retyped; only values change.What to change: Nothing. A client that cached one of these games can read it again for the crests and ids.
Quotes and snapshots say when reading again will not bring a market's live book
GET /api/v1/games/{event_slug}/markets with expand=quotes adds book_unavailable_reason to each outcome’s quote, and GET /api/v1/market/{condition_id}/snapshot adds the reason stream_capacity.We always stream Polymarket’s order book for the sports boards and for liquid games around kickoff. Any other open market gets a live book when you read it, up to a shared number of markets that API reads can hold at once. Before this change, a read past that number answered like a first read (unavailable on a quote, cache_miss on a snapshot), so reading again looked as if it would help, and it did not. On November 4, one read of every active market of the 23 live games asked for 359 markets against room for 100, and 31 markets with a two-sided Polymarket book stayed unavailable.
  • quote.book_unavailable_reason is null when book_observed_at is set. Otherwise it is cache_miss (no book held yet; read again after a few seconds), stream_capacity (API reads already hold every live book they can open; reading again does not help until fewer markets are read), no_orderbook or missing_provider_token_id.
  • The snapshot’s outcomes[].top_of_book.reason and freshness.top_of_book.reason read stream_capacity instead of cache_miss in the same case.
  • A market we always stream no longer takes one of those places when you read it, so more of the markets you read get a live book.
  • The list_game_markets MCP tool, the SDK types and the OpenAPI document describe the same.
Backward compatible. book_unavailable_reason is a new key, and stream_capacity is a new value of an existing string field. A client that treats an unknown snapshot reason as “no book” keeps working.What to change: If you poll many markets, read book_unavailable_reason: on stream_capacity, read fewer markets, or that one less often, instead of retrying it.
Quotes and snapshots serve a book with one side or no orders, not unavailable
GET /api/v1/games/{event_slug}/markets with expand=quotes now serves an outcome whose Polymarket order book holds orders on one side only, or none, as observed: the side with orders carries its best price, an empty side is null, and book_observed_at is set. GET /api/v1/market/{condition_id}/snapshot names the same books in top_of_book.reason.Before this change, such an outcome read unavailable with every figure null, and the snapshot read cache_miss, for as long as the book stayed that way; a later read did not fill it. On November 4 that was about 260 empty and 60 one-sided books across the live games.
  • quote.status is observed with book_observed_at set and a null best_bid (no bids) or best_ask (no asks), or both null for an empty book. price is unchanged.
  • The snapshot’s top_of_book.status stays available only for a book with both sides. A book with one side is unavailable with reason one_sided_book and carries that side’s best_bid or best_ask, with no spread or depth; an empty book is unavailable with reason empty_book.
  • freshness.top_of_book.reason takes the same values: one_sided_book when either outcome’s book has one side, then empty_book, then cache_miss.
  • The list_game_markets MCP tool and the OpenAPI document describe the same.
Backward compatible for a client that reads status and reason first. A client that took a present snapshot best_bid or best_ask to mean a two-sided book now also sees one beside unavailable.What to change: Nothing, unless you read snapshot prices without checking top_of_book.status; then check it. To tell an empty side from a missing figure on a quote, read book_observed_at.
Finished tennis doubles games from October 17 to 31 name both pairs as the two sides
A finished ATP or WTA doubles game in GET /api/v1/games/{event_slug} and GET /api/v1/games now names each side by its pair, such as Bolelli/Vavassori, with the pair’s provider_id and logo. This applies to doubles games whose stored live score was written before October 31, 2026.Before this change, such a game named one player on each side, often the two partners of one pair, and the other pair was missing:
  • Bolelli/Vavassori vs. Andreozzi/Guinard on October 30 served Simone Bolelli (no provider_id) against A. Vavassori, with his singles id 625505, the Italian flag and a record.
  • 272 doubles games played October 17 to 31 were affected, 201 ATP and 71 WTA. In 234 of them coverage.competitors was labels. The other 38 carried singles players’ ids.
Each of these games now serves its two pairs:
  • How a side is matched: by the pair code in the game’s slug (bolevav, andrgui), in the slug’s order, as for doubles games stored since October 31. This applies only while both sides’ scores are 0, the placeholder Polymarket sends for doubles games. A side with a real score keeps its stored name.
  • name, provider_id, logo: the pair’s, as on other doubles games. record is null: the stored record was the player’s.
  • coverage.competitors: provider_ids when both pairs are found.
  • Doubles games whose stored score already names the pairs are unchanged.
Backward compatible. No field was added, removed or retyped; only values change.What to change: Nothing. A client that cached one of these games can read it again for the corrected sides.
Finished games whose stored score names a side by an unknown code, or as the wrong team, name each side's team
A finished game in GET /api/v1/games/{event_slug} and GET /api/v1/games now names each side by the team the game’s moneyline names, with its provider_id and logo. This applies when the stored live score names the side by a code no team carries, or carries another team’s identity.Before this change, such a side kept what the stored score said:
  • Air Force vs. Wyoming on October 23 served the codes AFA and WYO, with provider_id and logo set to null and coverage.competitors set to labels. So did 132 other college football games, two NHL games and one CS2 game.
  • Two South Dakota State games served that side as San Diego State: its name, id 212, logo and record.
  • A CS2 side was named GODS PLAN (id 139465) beside Joga de terno’s logo.
Each of these games now serves both teams of its moneyline:
  • How a side is matched: by its code or name against the two teams of the game’s stored team pair, or as the one team left once the other side is named. When neither side names a team, the settled moneyline decides: in a final score by points, the side with the higher score is the team that won. A side is never given a team by its position.
  • When it applies: only when the moneyline’s two outcomes name the pair’s two teams, one each. A game whose stored pair disagrees with its outcomes is unchanged.
  • name, provider_id, logo: the matched team’s, as on other finished games. In college football name is the school (Air Force), not the mascot.
  • record: null where the stored score carried another team’s record. Elsewhere it stays the record stored at the game.
  • coverage.competitors: provider_ids when both sides carry a team.
  • Tennis doubles games that showed one pair’s two partners as the two sides have their own entry.
Backward compatible. No field was added, removed or retyped; only values change.What to change: Nothing. A client that cached one of these games can read it again for the corrected sides.
Game markets carry each market's fees, liquidity rewards, order delay and tick with expand=trading_terms
GET /api/v1/games/{event_slug}/markets takes expand=trading_terms, which adds trading_terms to every row: the market’s fee schedule, liquidity reward settings and allocations, order delay and tick, as Polymarket’s market record states them, with the time it was read.Before this change, a client that quotes a game’s lines had to read each market from Polymarket’s Gamma or CLOB API to learn what it pays and how long a marketable order waits.
  • status: observed, not_listed (Polymarket’s market list returned no record for the market) or unavailable (no read yet; every figure is null, and a read a few seconds later usually answers).
  • fees_enabled and fee_schedule: rate, exponent, taker_only and rebate_rate, the fraction of taker fees rebated to the resting maker.
  • rewards_min_size (shares), rewards_max_spread (cents from the midpoint) and reward_allocations, each with rewards_amount, rewards_daily_rate, start_date and end_date.
  • seconds_delay: how many seconds a newly placed marketable order waits before it can match. Polymarket sets it on sports markets around live play.
  • tick_size and observed_at. Each market’s read is refreshed about once a minute.
  • It works on every plan and adds 1 to the request cost: 3 with trading_terms, 4 with quotes too.
  • The list_game_markets MCP tool takes "trading_terms" in its expand array. The OpenAPI document and the SDK types describe the block.
Backward compatible. trading_terms appears only when you send expand=trading_terms, and every key in it is always present; null means unknown. Without the expand, the response is unchanged.What to change: Nothing. To read a game’s fees, rewards and order delay in one request, send expand=trading_terms.
Finished games filtered by a small league reach the end in a few pages
GET /api/v1/games with status=ended, cancelled or postponed and a league filter now reads only the games that league can hold, so a small league inside a large sport no longer spends each page on the sport’s other games.Before this change, the league filter ran after a page’s read budget, which counted every game of the league’s sport. league=ukr1 read through all of Soccer, and most of its pages came back empty with has_more: true. Paging kickoffs from October 21 to November 4 with limit=100, on a copy of production data, before and after:
  • league=ukr1: 21 pages (15 empty) before, 8 pages (4 empty) after, the same 13 games.
  • league=enl: 16 pages (7 empty) before, 5 pages (none empty) after, the same 34 games.
  • league=taipei: 24 pages (19 empty) before, 5 pages (2 empty) after, the same 39 games.
  • league=cfb, league=epl and sport=Football return the same games in the same pages or fewer.
Backward compatible. Rows, their order and the cursor format are unchanged; only where a page ends moves. A page can still be short, or empty, while has_more is true.What to change: Nothing. Keep following next_cursor until has_more is false.
Game markets carry each outcome's price, best bid and best ask with expand=quotes
GET /api/v1/games/{event_slug}/markets takes expand=quotes, which adds a quote to every outcome on the page: the price Polymarket shows, and the best bid and best ask, each with the time it was observed.Before this change, a game’s spreads, totals and props carried no price, so a client had to call Polymarket’s CLOB, or read Market snapshot once per market.
  • status: observed (we hold the price, the book or both; a null figure beside it is one we do not hold), no_orderbook (Polymarket confirmed the outcome has no order book and we hold no price) or unavailable (we hold nothing for it yet; every figure is null, and a read a few seconds later usually answers, because the request starts covering the page’s open markets).
  • price, from 0 to 1, with price_basis: midpoint when the best bid and ask are at most $0.10 apart, otherwise last_trade. price_observed_at is when the quote and trades behind it were observed. These are the figures Market snapshot serves as current_price, at full precision.
  • best_bid and best_ask, from 0 to 1, with book_observed_at, when Polymarket’s book update behind them was observed.
  • It works on every plan and adds 1 to the request cost: 3 with quotes, 6 with sharp_money too.
  • The list_game_markets MCP tool takes "quotes" in its expand array. The OpenAPI document and the SDK types describe the block.
Backward compatible. quote appears only when you send expand=quotes, and every key in it is always present; null means unknown. Without the expand, the response is unchanged.What to change: Nothing. To price a game’s lines in one request, send expand=quotes, and read again a few seconds later for an outcome that reads unavailable.
Finished tennis games keep their tournament as league in /api/v1/games
GET /api/v1/games and GET /api/v1/games/{event_slug} now give a finished game the league the live board gave it: the provider event’s own league, which in tennis is the tournament (taipei, pan pacific open). Esports and cricket games outside a league scope (cs2, lol and the other scope leagues keep theirs) read their event’s league the same way.Before this change, a finished game read from its stored rows took the tour instead (atp, wta, itf or challenger), so a game changed league when it left the board, and league=taipei&status=ended found none of a tournament’s finished games. A few ended tennis games still on the board also read challenger.Breaking for clients that read or filter finished tennis games by a tour code: league=wta&status=ended no longer matches a game whose event names its tournament.What to change: Filter finished games by the tournament, as you do for upcoming and live ones, and use sport=Tennis to read every tour.
Games, the game detail and the market snapshot carry each market's settlement
GET /api/v1/games/{event_slug} and GET /api/v1/market/{condition_id}/snapshot now carry settlement, the block List game markets returns, and GET /api/v1/games carries it with expand=settlement.Before this change, only the game markets route said how Polymarket’s oracle settled a market, so a client reading games or a snapshot had to make a second call to learn which side paid or whether a market settled 50-50.
  • GET /api/v1/games/{event_slug}: every winner market carries settlement, also for a finished game read after it leaves the live board. The request cost stays 2.
  • GET /api/v1/games: expand=settlement adds it to every winner market on the page, on every plan, and adds 2 to the request cost. It combines with expand=sharp_money. Without it, markets carry no settlement key.
  • GET /api/v1/market/{condition_id}/snapshot and its Markdown twin: a top-level settlement, read from the market’s event, or from its game for a market Polymarket files under a child event. market.market_result stays null.
  • None of these reads waits for Polymarket. A game no read has asked about lately reads status unavailable, and its read starts at once, so a read a second or two later carries the block.
  • The list_games, get_game and get_market_snapshot MCP tools, the OpenAPI document, the SDK types and the sandbox describe the field. The list_games tool’s expand now also takes an array, ["sharp_money", "settlement"], for both blocks in one call; one value works as before.
Backward compatible. settlement is a new field, expand=settlement is a new value, and a single expand value is still accepted.What to change: Nothing. To settle a position from a game or a snapshot read, read settlement.result and settlement.payouts, and treat unavailable as “ask again shortly”, never as unsettled.
Upcoming college football games name each side by its school, not its mascot
An upcoming college football game in GET /api/v1/games and GET /api/v1/games/{event_slug}, and in the MCP list_games and get_game tools, now names each side by its school.Before this change, such a game named its sides by mascot until kickoff, and by school once it was live or finished. Ball State vs. UMass on November 4 read Cardinals and Minutemen in competitors[].name and outcome_yes, while the same response’s title (Ball State vs. UMass), its prices.provider labels and Polymarket’s moneyline outcomes read Ball State and UMass. Several schools share a mascot, so a mascot alone can name the wrong team: Eagles is Eastern Michigan, Boston College and Georgia Southern.
  • competitors[].name, markets[].outcome_yes and markets[].outcome_no: the school (Ball State), as the moneyline outcomes name it. A team keeps one name before kickoff, in play and after the game ends.
  • markets[].prices.provider.binding_provenance: exact_labels for a game Polymarket lists without team ids, where it read elimination or null. Prices are unchanged, except that a pair refused as invalid with final_identity_mismatch because its names disagreed is now paired at Polymarket’s prices (Morehead State vs. Marist on November 7).
  • provider_id, logo, record and side are unchanged.
  • Every other league is unchanged, college basketball included: its names already carry the school (Southern Indiana Screaming Eagles).
Backward compatible. No field was added, removed or retyped. Only values changed for upcoming college football games: their side names and, for a game without team ids, the recorded way its prices were matched.What to change: A client that matched an upcoming college football side by its mascot should match by provider_id, or by the school name now served.
Finished games with no stored score carry each side's team id and logo
A finished game in GET /api/v1/games/{event_slug} and GET /api/v1/games that has no stored live score now carries provider_id and logo for each side its moneyline names, when the game’s stored team pair includes that team.Before this change, such a game named its competitors from the moneyline’s two outcomes only, with provider_id and logo set to null and coverage.competitors set to labels. Western Kentucky vs. Sam Houston on October 14 is one example. The change reaches every sport: in a read of ten leagues on November 4, 468 of 1,586 finished games moved from labels to provider_ids, most of them table tennis (306) and tennis singles (102).
  • name: unchanged. It stays the outcome’s name, which in college football is the school (Western Kentucky), not the mascot.
  • provider_id and logo: set when the outcome names one team of the game’s team pair, by its exact name, alias or code, or by its words. A side is never given a team by its position. For a tennis or table tennis player, logo is the player’s country flag, as on games with a stored score.
  • coverage.competitors: provider_ids when both sides carry a team, else labels.
  • A game whose legs store no team pair, such as Columbia vs. Penn on October 16, is unchanged.
Backward compatible. No field was added, removed or retyped; only values that were null are now set.What to change: Nothing. A client that matches finished games to teams by name can use provider_id for these games too.
Finished games filtered by sport or league reach the end in far fewer pages
GET /api/v1/games with status=ended, cancelled or postponed and a sport or league filter now spends each page’s read on the filtered sport’s games, so a page reaches several days of kickoffs instead of under one.Before this change, a page’s read budget counted every sport’s games, and the filter dropped the others afterwards. A filtered walk of two weeks came back as dozens of pages, most of them empty with has_more: true. Paging kickoffs from October 21 to November 4 with limit=100, before and after:
  • league=cfb: 51 pages (37 empty) before, 4 pages (none empty) after, the same 225 games.
  • league=nba: 51 pages (29 empty) before, 5 pages (none empty) after, the same 104 games.
  • sport=Football: 12 pages before, 5 after, the same 259 games.
  • league=ukr1: 51 pages (42 empty) before, 18 pages (12 empty) after, the same 13 games. A small league inside a large sport still takes several short pages.
Backward compatible. Rows, their order and the cursor format are unchanged; only where a page ends moves. A page can still be short, or empty, while has_more is true.What to change: Nothing. Keep following next_cursor until has_more is false. A league with no game on the live board reads every sport, as before: pass sport beside it (sport=Esports&league=iem) to narrow the read.
Finished games in /api/v1/games name each side and serve its current crest
A finished game in GET /api/v1/games/{event_slug} and GET /api/v1/games now names its competitors through the same team binding a live game uses, so name, provider_id and logo match the live board.Before this change, a game the board had dropped served its sides exactly as the last live score stored them. Penn carried Polymarket’s generic ESPN college football image, and Duke, Virginia and Yale an older crest file.
  • logo: generic provider artwork is dropped, and a team with a current college or supplemental crest serves it.
  • provider_id and name: a side whose score-feed code names its team, or the one side left once the other is named, carries that team’s id and name. coverage.competitors can change from labels to provider_ids.
  • score and record are unchanged: they stay the final score and the record stored at the game.
  • A game whose two sides both carry codes that name no team, such as AFA and WYO, still serves those codes with no logo.
Backward compatible. No field was added, removed or retyped; only values change.What to change: Nothing. A client that cached a finished game’s logo or provider_id can read the game again for the corrected values.
Game markets carry each market's settlement: oracle status, payouts and 50-50
Every row of GET /api/v1/games/{event_slug}/markets now carries settlement: how Polymarket’s oracle settled, or is settling, the market, from Polymarket’s /v2/resolutions.Before this change, a row said only active or closed, so a client had to call Polymarket to learn which side paid, whether a market settled 50-50, or whether a proposal was disputed.
  • status: observed (Polymarket’s resolution row is below), not_posed (no oracle request yet; settled is false) or unavailable (no read in hand; every other field is null, and a read a moment later may answer).
  • oracle_status: Polymarket’s lifecycle state as Polymarket writes it, such as proposed, disputed or resolved. settled is true when it is resolved.
  • payouts: what one share of each outcome pays, in micro-USDC (1000000 is $1), in outcome index order. It is set only on a resolved row that carries payouts.
  • result: outcome (one side paid in full; winning_outcome_index names it) or split (Polymarket’s 50-50), read off payouts only.
  • was_disputed, resolved_at, and for a pending market expected_settlement_time with settlement_time_basis: Polymarket’s estimate of the earliest settlement, not a deadline.
  • proposed_answer: outcome_0, outcome_1, split or too_early, the newest proposal of a pending round. A proposal is not a result.
  • observed_at: when Polymarket answered. A settled read is refreshed every 10 minutes, any other every minute.
  • The list_game_markets MCP tool, the OpenAPI document, the SDK types and the sandbox describe the block. The request cost stays 2.
Backward compatible. settlement is a new field, and every key in it is always present; null means unknown.What to change: Nothing. To settle a position without calling Polymarket, read settlement.result and settlement.payouts, and treat unavailable as “ask again shortly”, never as unsettled.
SDK 0.39.0 sends the stream's min_grade_at_trade filter
@0xinsider/sdk 0.39.0 adds min_grade_at_trade to StreamFilters, so streamFeed, streamFeedResilient and consumeStreamCheckpointed can send the GET /api/v1/stream filter of the same name.Before this release, the SDK’s only grade filter on the stream was min_grade, which reads the wallet’s grade when the trade was published, hours after the fill for a backfilled trade. A client that caught up on GET /api/v1/large-trades/history with min_grade_at_trade could not stream on the same basis through the SDK.
  • min_grade_at_trade keeps a LargeTradeInsertedV2 frame only when its grade_at_trade is at or above the value and its grade_at_trade_status is graded. With it set, every other frame type is excluded.
  • Sending it beside min_grade is refused with 400 bad_request and param min_grade_at_trade. The resilient consumers do not retry it.
  • The same release types min_grade_at_trade on listLargeTrades, listLargeTradeHistory, getEventReplaySince and webhook trade_filters, and grade_at_trade and grade_at_trade_status on LargeTradeInsertedV2Data.
  • It also types scores_freshness and scores_age_seconds on games.
Backward compatible. The filters and fields are new, and no existing one changed.What to change: Upgrade to 0.39.0. To catch up on large trades and then stream on one basis, send min_grade_at_trade instead of min_grade on both.
Games scores_freshness reads stale for esports, college basketball and NHL games
GET /api/v1/games and GET /api/v1/games/{event_slug} now judge freshness.scores_freshness for esports, college basketball and NHL games, and read not_applicable in a break between periods. The list_games and get_game MCP tools carry the same values.Before this change, only a running soccer half could read fresh or stale. Every other live game read unknown, including an NHL game in an intermission.Each bound is about twice the longest gap between frames that we measured on November 4, 2026:
  • Esports (league cs2 or lol): stale after 120 seconds with no frame while the series is in progress. The provider resends each running series about every 20 seconds, also while the map score does not move.
  • Men’s and women’s college basketball (cbb, cwbb) and NHL hockey (nhl): stale after 600 seconds with no frame while a period’s clock is running. These feeds send no frame while the clock is stopped for a timeout or review.
  • Breaks: a period of HT or End ... (for example End P2 or End Q2) reads not_applicable. In women’s college basketball, End OT is the end of the third quarter and the provider sends no frame for the fourth, so it reads unknown.
  • Still unknown: tennis, college football, the NBA, the NFL, other esports titles, and every other league with no measured bound.
scores_age_seconds is the time since the game’s last frame. For esports that is the last resend, not the last change in the score.Backward compatible. No field is added or removed. Some live games that read unknown now read fresh, stale or not_applicable.What to change: Nothing, if you already show a live score as delayed when scores_freshness is stale.
@0xinsider/mcp 3.13.0 is published; local large-trade tools filter on the grade at the fill
@0xinsider/mcp 3.13.0 is on npm and in the MCP Registry. It brings the November 4 changes listed below to the local MCP server and the CLI.
  • get_large_trades, get_large_trades_history, get_event_replay_since and the deprecated aliases get_whale_trades and get_whale_trades_history take min_grade_at_trade, the grade the trader held when the trade filled. Sending it with min_grade returns bad_request.
  • 0xinsider api list names min_grade_at_trade for listLargeTrades, listLargeTradeHistory and getEventReplaySince. The entry “Large trades, the stream and webhooks can filter on the grade a trade filled under” said it would name it for getStream too, but api list and api call leave out the stream, which you read from GET /api/v1/stream directly.
  • The get_pick_of_the_day description says a pick_id call returns the pick once, in picks[0], as the API already did.
  • The bundled SDK types describe every sport leaderboard field.
The local server lists the same 69 tools as the remote server. The CLI, MCP and introduction pages now install @0xinsider/mcp@3.13.0.Backward compatible. Every change adds a parameter, a section or a description; no tool, default or field changed.What to change: Run npm install --global @0xinsider/mcp@3.13.0, or change a client’s @0xinsider/mcp@3.12.0 argument to @0xinsider/mcp@3.13.0. 0xinsider --version prints 3.13.0 once the update is in place.
Games add scores_freshness and scores_age_seconds, so a frozen live score no longer reads fresh
GET /api/v1/games and GET /api/v1/games/{event_slug} now send freshness.scores_freshness on every game, plus freshness.scores_age_seconds when a Sports WebSocket frame dates the score. scores_age_seconds is the time since that game’s last frame, which is how long its score, period and clock have gone unchanged. The list_games and get_game MCP tools and the TypeScript types carry both.Before this change, source_freshness was the only freshness value. It dates the board as a whole, so it read fresh while one live game’s clock and score were 14 minutes old.scores_freshness is judged on the game clock:
  • stale: a soccer half’s clock is running and no new frame has arrived for more than 180 seconds. The provider sends a frame each match minute.
  • fresh: a running soccer half’s clock had a frame within that bound.
  • not_applicable: the game is not in play (scheduled, final, postponed or cancelled), or it is at halftime.
  • unknown: no frame dates the score, the game is in stoppage time, or the game’s sport has no measured bound. Basketball and hockey clocks stop for timeouts and reviews, so those sports read unknown.
Backward compatible. Both fields are additive.What to change: If you show a live score, show it as delayed when scores_freshness is stale. Treat unknown as unverified, never as current.
Scheduled games and live soccer games now carry sports_market_type and side on their markets
GET /api/v1/games and GET /api/v1/games/{event_slug} now send sports_market_type (the provider’s own value, for example moneyline) and side on the markets of a game that has not started, and on soccer markets while the game is live.Before this change, those markets left out both fields. A client that picked a game’s moneyline by sports_market_type found no market on any scheduled game. Measured on November 4, 2026: 0 of 100 scheduled esports markets carried the field.side is still left out when the provider does not identify the competitors (no provider ids, as on many ITF tennis matches). The live markets work the same way.Backward compatible. Both fields were already documented and are now sent where they were missing.What to change: Nothing. If you fall back to the only listed market when sports_market_type is missing, you can now select by sports_market_type === "moneyline" instead.
Large-trade history and the event replay can filter on the grade a trade filled under
GET /api/v1/large-trades/history and GET /api/v1/events/feed/since accept min_grade_at_trade. It keeps a trade only when the grade its trader held when the trade filled is at or above the value, the rule GET /api/v1/large-trades, GET /api/v1/stream and webhook trade_filters already apply.Before this change, both routes offered only min_grade, which reads the wallet’s grade when the page is read. A client that caught up through one of them and then streamed with min_grade_at_trade could get a different set of trades.
  • Only a trade whose grade at the fill is graded matches. A trade before September 19, 2026, 23:00 UTC is unknown and never matches.
  • On the history route it works with both sorts and beside condition_id, event_slug, trader, from and to.
  • On the event replay it is bound to the cursor like the other filters: a cursor minted under min_grade and presented with min_grade_at_trade, or the reverse, returns 400 with error.reason cursor_expired. meta.replay.filters echoes it.
  • Sending min_grade and min_grade_at_trade together returns 400 with param min_grade_at_trade.
  • The remote MCP tools get_large_trades_history, its deprecated alias get_whale_trades_history, and get_event_replay_since take min_grade_at_trade now. The next @0xinsider/mcp release adds it to the local MCP tools, and 0xinsider api list will name it for listLargeTradeHistory and getEventReplaySince.
  • The next SDK release adds min_grade_at_trade to StreamFilters, sent as the min_grade_at_trade query parameter of GET /api/v1/stream.
  • min_grade keeps its meaning on every surface.
Backward compatible. The parameter is new, and every cursor minted before it continues unchanged.What to change: Nothing. To catch up and stream on one basis, send min_grade_at_trade instead of min_grade on the history or replay read and on the stream.
@0xinsider/mcp 3.12.0 is published; Pick of the Day tools default to the summary view
@0xinsider/mcp 3.12.0 is on npm and in the MCP Registry. It brings the November 3 changes listed below to the local MCP server and the CLI. Before this release, the local server ran 3.11.0, whose Pick of the Day tools sent no view and returned the whole record: 198,807 bytes for one day’s 14 picks.
  • get_pick_of_the_day, get_pick_of_the_day_archive and get_pick_of_the_day_stats send view=summary unless you name a view. They take pick_id, the archive’s limit and cursor, and the stats sections.
  • get_leaderboard describes the board summary (ranked_total, by_grade, active_30d, as_of), sent on a page with no category or strategy.
  • get_edge_hunter reads category: "sports", in any casing, as kind: "sports" in every view. explore_markets and get_leaderboard take sports for every sport but Esports, and the market and trade tools that reject the word say to omit category instead.
  • get_trader takes expand: ["breakdowns"] and describes price_edge, the edge over the price paid that the profile badge shows.
  • Each get_game_holders item’s data carries stale.
  • The package’s MCP Registry description reads “Polymarket sports and esports data: wallet grades on settled P&L, large trades, markets.”
The local server lists the same 69 tools as the remote server. The CLI, MCP and introduction pages now install @0xinsider/mcp@3.12.0. The November 4 pick_id change to Pick of the Day needs no package update: the local get_pick_of_the_day passes the API body through, so a pick_id call returns the pick once, in picks[0].Breaking for local MCP clients that read Pick of the Day fields the summary leaves out, such as display_holders or entry_authorization. The other changes add parameters, fields and descriptions.What to change: Run npm install --global @0xinsider/mcp@3.12.0, or change a client’s @0xinsider/mcp@3.11.0 argument to @0xinsider/mcp@3.12.0. For the full Pick of the Day body, send view: "full", or call get_pick_of_the_day with pick_id for one pick in full. 0xinsider --version prints 3.12.0 once the update is in place.
Sandbox leaderboard lists S, A and B only, with a ranked edge for each grade
In the sandbox, GET /api/v1/leaderboard now returns 5 rows graded S, A and B, the grades the live leaderboard lists. Each of the 3 grades has a price_edge with status: "ranked" and no hold, the edges sort=edge ranks.Before this change, the sandbox leaderboard returned 7 rows graded S to D. Every price_edge had status: "ranked", hold: "record_incomplete" and edge: 1, so a client that keeps only ranked edges with no hold found none.
  • One A edge keeps hold: "record_incomplete", and one B edge has status: "sample_mismatch".
  • price_edge.edge is hit_rate minus avg_price, as the field is defined. hold is omitted when nothing holds the edge, as in the live API.
  • In POST /api/v1/traders/batch, a sandbox wallet’s price_edge has the same figures, with shrunk_edge and field_average only when the edge ranks.
  • The sandbox leaderboard’s total is 5, so a limit=3 walk ends on its second page.
Backward compatible. Response shapes are unchanged. Sandbox values now match what the live API can return.What to change: Nothing. A sandbox client that expected 7 leaderboard rows, or a C or D row, now gets 5 rows graded S, A and B.
OpenAPI describes every sport leaderboard field: grade is all-time, P&L is in-sport
The OpenAPI schemas for the sport leaderboard and leaderboard leagues now describe every field, including each row field and each price_edge field.Before this change, both schemas listed field types only. A reader could not tell from the schema that a row’s grade is the wallet’s all-time grade while its other figures are in the sport or league. On the esports board sorted by P&L on November 4, the top wallet had $3,692,604 in esports P&L and an F grade.
  • grade: the all-time grade, led by realized profit across all of the wallet’s sports and esports markets, not this sport’s.
  • pnl, cost, roi, wins, losses, win_rate, price_edge, edge_skill: the wallet’s record in this sport or league. roi and win_rate are fractions: 0.12 is 12%.
  • volume: the wallet’s volume across all sports and esports on a sport board, as volume_scope says, and null on every league board row.
  • total_traders: wallets with at least min_resolved settled markets here and a trade in the last 180 days.
Backward compatible. Only descriptions change. Field names, types, required fields and responses are unchanged.What to change: Nothing. Refresh cached OpenAPI documentation or generated clients to pick up the descriptions.
Large trades, the stream and webhooks can filter on the grade a trade filled under
GET /api/v1/large-trades, GET /api/v1/stream and webhook trade_filters on POST /api/v1/webhooks accept min_grade_at_trade. It keeps a trade only when the grade its trader held when the trade filled is at or above the value, by the same rule on all three.Before this change, each min_grade read a different grade: the list read the wallet’s grade now, and the stream and webhooks read its grade when the trade was published. A client that caught up on the list and then streamed got two answers: over 16 hours on November 3 the list added 2 trades and dropped 3 against the stream. Publication can also come hours after the fill: in the 7 days to November 3, 14 of 3,892 trades were published under a different grade than they filled under.
  • The LargeTradeInsertedV2 stream frame and the large_trade_inserted_v2 webhook data add grade_at_trade and grade_at_trade_status, the same facts as trader.grade_at_trade and trader.grade_at_trade_status on the list. grade is unchanged.
  • Only a trade whose grade_at_trade_status is graded matches. A trade before September 19, 2026, 23:00 UTC is unknown and never matches, and neither does an event published before this change. Such an event, redelivered, carries neither field, so read both as optional.
  • On the list, min_grade_at_trade works with since, sort=market_volume_share, condition_id and event_slug.
  • On the stream, min_grade_at_trade passes only LargeTradeInsertedV2 frames. min_grade also passes wallet_grade_changed frames.
  • Sending min_grade and min_grade_at_trade together returns 400 with param min_grade_at_trade (trade_filters.min_grade_at_trade on webhooks).
  • The remote MCP tool get_large_trades and its deprecated alias get_whale_trades take min_grade_at_trade now. The next @0xinsider/mcp release adds it to the local MCP tools, and 0xinsider api list will name it for listLargeTrades and getStream.
  • min_grade keeps its meaning on every surface.
Backward compatible. The parameter and the two payload fields are new.What to change: Nothing. To get the same trades from the list, the stream and webhooks, send min_grade_at_trade instead of min_grade on each. A stream client that also reads wallet_grade_changed frames gets them only on a connection without min_grade_at_trade.
Games reports a cancelled or postponed upcoming game as cancelled or postponed
GET /api/v1/games and GET /api/v1/games/{event_slug} now report status.state cancelled or postponed when Polymarket marks an upcoming game that way. window=now leaves those games out, as it already did for every cancelled and postponed game.Before this change, a game that Polymarket marked only on its event, with no live-score update, read scheduled. On November 3, 2026, Paine at Jacksonville (cbb-pain-jax-2026-11-02) was cancelled and still read scheduled 23 hours after its listed tip-off.An upcoming game whose provider period this API does not recognize now reads unknown, not scheduled. No game read that way on November 3, 2026.Backward compatible. Both values were already in the status.state enum, and no field is added or removed.What to change: Nothing. If you list upcoming games and treat every game that is not live as still to be played, check for cancelled and postponed too.
Pick of the Day with pick_id returns the pick once, in picks[0]
GET /api/v1/pick-of-the-day with pick_id now returns that pick once, as picks[0], beside state, pick_date and pick_count. The remote MCP tool get_pick_of_the_day with pick_id returns the same body.Before this change, the pick_id body also copied the pick’s fields to the top level, the way a whole-day read repeats its first pick. That doubled the body. On November 2, 2026, the largest pick was 42,388 characters, and 7 of the 14 picks were over 25,000. Without the copy the largest is about 21,150.Breaking only for clients that read pick fields, such as entry_authorization or display_holders, from the top level of a pick_id body. pick_id was added on November 3, 2026. A request without pick_id returns the same body and ETag as before.What to change: Read the pick from picks[0].