Skip to main content
These are the API changelog entries from October 6 to 11, 2026, newest first. The newest changes are on the API changelog.
Max-only Edge Hunter replaces 4 retired sports signals and observations endpoints
GET /api/v1/edge-hunter now returns the ranked board shown on Edge Hunter. It requires Max; a Pro credential returns 403 forbidden with error.reason: max_plan_required.Before this change, sports signals and observations were separate paginated APIs. These 4 paths now return 410 Gone with error.code and error.reason set to endpoint_retired:
  • /api/v1/sports-edge-signals
  • /api/v1/sports-edge-observations
  • /api/v1/sports/pre-game-sides
  • /api/v1/sports/pre-game-side-observations
Edge Hunter uses object: "edge_hunter" and returns data.rows, with up to 30 full rows across all sports. horizon_hours defaults to 48 and is clamped to 1 through 48; the grade floor is fixed at B, and data.total counts matches before the row cap.The response includes market and participant identities, backed-side analytics, and current quotes when available. It has no cursor, category filter, observation cohort, or observation funnel.The client packages and official agent instructions use the new API:
  • SDK 0.20.0 adds getEdgeHunter and edgeHunter.get(), and removes the old sports signals and observations helper methods.
  • The MCP and CLI runtime 3.0.0 adds get_edge_hunter; the 4 old MCP tools are no longer advertised.
  • The official agent plugin’s polymarket-sharp-money skill, version 1.0.2, now calls Edge Hunter and requires Max for board requests.
Breaking for clients that call any of the retired REST endpoints or MCP tools.What to change: Use /api/v1/edge-hunter with a Max credential, or get_edge_hunter over MCP. Read data.rows and the new board fields, remove unsupported filters and cursors, and update to SDK 0.20.0 or MCP 3.0.0.Refresh installed official skills with npx skills@latest update 0xinsider-api-access polymarket-sharp-money. Stop retrying 410 endpoint_retired.
Market snapshot starts a live book on the first read of a market off the sports boards
GET /api/v1/market/{condition_id}/snapshot always streams the order book for two groups of markets. The first is every market on the 0xinsider sports boards. The second is every sports market with $10,000 or more of liquidity, from 15 minutes before kickoff until it resolves. A market in either group whose book has no bid or no ask, such as a finished game waiting to resolve, still reports cache_miss.Any other open market, such as a non-sports market, a futures market, or a sports market long before kickoff, now gets its book when you read it. Before this change the cache also held every other open market with $10,000 or more of liquidity. The first snapshot of such a market starts a live subscription and reports no book:
  • outcomes[].top_of_book.status is unavailable, with reason: "cache_miss".
  • outcomes[].current_price is null, because it is the midpoint of that book.
  • freshness.top_of_book and the trust expansion report the book unavailable.
A snapshot a few seconds later has the live book. The market keeps its live book while you read it at least once every 5 minutes. When many markets are held at the same time, a read can fail to start a subscription, and the snapshot keeps reporting cache_miss.Backward compatible. Each of these values was already possible.What to change: Nothing, if you already handle a missing book. If you get cache_miss for an open market, read the snapshot again after a few seconds.
Tennis headshot images are served at most 128 px wide
The tennis headshot URL that GET /api/v1/pick-of-the-day returns on a competitor now serves an image at most 128 px wide. The image keeps its aspect ratio and is never enlarged. Before this change the URL served the stored portrait, up to 1024 px wide.
  • The URL and its v query parameter are unchanged.
  • The response is image/png. A portrait that was stored as JPEG used to be served as image/jpeg and is now PNG too. An image already 128 px or smaller is served as stored, with its stored type.
  • The ETag is now the image hash followed by -w128, for example "<sha256>-w128". A cached copy that holds the old tag (the bare hash) gets a 200 with the new image, not a 304.
Backward compatible for clients that show the headshot at 128 px or smaller.What to change: Nothing, unless you show the headshot larger than 128 px. In that case the image is scaled up by your client.
Report large trades name Yes and No outcomes instead of null
GET /api/v1/reports/daily, /weekly and /monthly now send "Yes" or "No" in outcome on report.top_large_trades[] and report.top_whale_trades[] when the traded market is a Yes/No market. Other markets keep their own labels, such as a team name.Before this change outcome was null for many Yes/No markets created since August 2026, because 0xinsider stored their labels as empty. Report snapshots built before this change keep the value they were built with.Backward compatible. outcome was already nullable, and it can still be null when no label is known.What to change: Nothing. If you replaced a null outcome with your own “Yes”/“No”, you can stop.
Trader context returns a retryable 503 instead of a 500 when its breakdown read times out
GET /api/v1/trader/{address}/context and GET /api/v1/trader/{address}/context.md now return 503 with error.reason: "read_model_warming" and Retry-After: 2 when the position_summary read runs out of time. That read covers every position the wallet has held, so a wallet with a long history can exceed its time limit when its data is not in the database cache. The API tries the read a second time before it answers, and the second try usually completes because the first one already loaded part of the data.Before this change, the same case returned 500 with error.code: "internal_error". On October 10, a client that retried two seconds after that 500 got a 200 both times it happened.
  • error.code is rate_limit_unavailable, the code every 503 on this API carries. Branch on error.reason.
  • The context is never returned without its position_summary for this reason, and a partial breakdown is never returned.
  • Any other database failure still returns 500.
Backward compatible for clients that already retry a 5xx response.What to change: Retry a 503 with error.reason: "read_model_warming" after the Retry-After seconds. Do not count it toward a rate-limit backoff.
Position timeline's trader_not_tracked message names the warm tier only
GET /api/v1/trader/{address}/position-timeline and GET /api/v1/traders/{trader}/position-timeline now end the trader_not_tracked message with only warm-tier traders are tracked. The warm tier is the set of wallets 0xinsider syncs most often.Before this change the message ended with only HOT and WARM traders are tracked. 0xinsider has moved every former hot-tier wallet to the warm tier and removed the hot tier, so the set of wallets with a timeline did not change.
  • error.code stays not_found and error.reason stays trader_not_tracked.
  • The message still names the trader’s own tier, for example (sync_tier=cold).
  • The OpenAPI descriptions, the SDK’s TraderNotTrackedError documentation, and the get_position_timeline MCP tool description say the same.
Backward compatible.What to change: Nothing, unless you match on the message text. Branch on error.reason instead.
Large trades name the real clock behind the volume data_quality group
GET /api/v1/large-trades and GET /api/v1/large-trades/history now send owner: "market_live_stats.volume_request_observed_at" on the volume entry of data_quality.field_groups. The deprecated /api/v1/whale-trades aliases send the same value.Before this change the entry named markets.volume_request_observed_at. That column is a retired copy. The as_of and status on the entry always came from market_live_stats, the table that holds each market’s volume and the time it was read, so only the name changes.Backward compatible for clients that read as_of and status. The ETag of a large-trades page changes once, because data_quality is part of it.What to change: Nothing, unless you match the owner string. If you do, match market_live_stats.volume_request_observed_at.
Pre-game sides and observations now need Max; Pro keys get 403 max_plan_required
GET /api/v1/sports/pre-game-sides and GET /api/v1/sports/pre-game-side-observations now need a credential on the Max plan. A Pro key gets 403 with code: forbidden, reason: max_plan_required, and a message that links the pricing page.Before this change, any Pro key could read both routes. They carry the same data as Edge Hunter, which the site has shown only to Max since October 8, 2026.
  • The deprecated aliases GET /api/v1/sports-edge-signals and GET /api/v1/sports-edge-observations answer the same way.
  • The MCP tools get_pre_game_sides, get_pre_game_side_observations, get_sports_edge_signals, and get_sports_edge_observations return the same error to a Pro key.
  • max_plan_required is a new value of error.reason. error.code stays forbidden.
  • The next @0xinsider/sdk release adds MaxPlanRequiredError, a ForbiddenError subclass with an upgradeUrl. Earlier versions throw ForbiddenError with reason set to max_plan_required.
  • Every other Pro endpoint keeps working with the same key.
Breaking for Pro clients that read pre-game sides or their observations.What to change: Upgrade to Max to keep reading these routes. Otherwise stop calling them, and treat reason: max_plan_required as a permanent refusal for that route, not as a deleted account.
Trader context.md prints one market win rate instead of two
GET /api/v1/trader/{address}/context.md now prints one Market win rate line, in the Performance section. When the position breakdown is present it is position_summary.resolved_win_rate, followed by its won and decided counts, for example - Market win rate: 3.4% (39 won of 1155 decided resolved markets). Otherwise it is trader.stats.win_rate.Before this change the document printed two lines for the same rule: Market win rate from trader.stats.win_rate, and Resolved-market win rate in the position breakdown. The stored figure could lag settled markets recorded after the wallet’s last full sync, so the two disagreed. On October 7, 34 of 400 ranked wallets differed by more than 0.5 points.
  • The Resolved-market win rate line is removed from the position breakdown.
  • freshness_note on GET /api/v1/trader/{address}/context, and the same sentence in the Markdown document, now say that resolved counts and win rate can include settled markets recorded after the last full sync.
  • The JSON body is otherwise unchanged. trader.stats.win_rate and position_summary.resolved_win_rate are both still sent.
Backward compatible for clients that read the JSON. Breaking for clients that parse the Resolved-market win rate line out of the Markdown document.What to change: Read the win rate from the Market win rate line, or from position_summary.resolved_win_rate in the JSON route.
Leaderboard realized_pnl is left out, never another P&L basis, without a native figure
GET /api/v1/leaderboard realized_pnl is now always the wallet’s own realized P&L, including credited maker and taker rebates. A wallet without that figure omits the field.Before this change, the documentation said such a wallet would carry an older stored realized P&L with a different basis. On October 10 every ranked wallet had the figure, so no response changed.
  • realized_pnl keeps its name, type and cent truncation.
  • The field was already optional. Treat its absence as “not available”, not as zero.
Backward compatible.What to change: Nothing, if your client already handles a missing realized_pnl.
@0xinsider/mcp 2.14.5 states the current tagline and bundles the combo SDK methods
@0xinsider/mcp 2.14.5 describes itself on npm and in its README as “Polymarket analytics & infrastructure for sports and esports markets”. The SDK copy bundled in the package (dist/sdk/) now includes client.combos.fills, client.combos.summary, and client.combos.get for the combo routes added on October 8, 2026. Its types follow the response changes listed in the entries since 2.14.4.Before this change, the npm description and README read “advanced tools for sports and esports markets, powered by Polymarket”, and the bundled SDK had no combo methods.
  • The 48 MCP tools, the CLI commands, and their output are unchanged. Neither calls the new methods.
  • The MCP Registry entry stays at 2.14.4, which serves the same tools.
Backward compatible.What to change: Nothing. Upgrading from 2.14.4 is optional.
Trader pnl.total and leaderboard pnl come from Polymarket's latest leaderboard observation
GET /api/v1/trader/{address} pnl.total and GET /api/v1/leaderboard pnl now carry Polymarket’s all-time leaderboard P&L from its latest observation of the wallet. When that leaderboard has no current observation ranking the wallet, the field is left out.Before this change, both fields read a stored copy that only some wallets kept current. For about 63,000 wallets it still held a figure from before Polymarket’s current leaderboard data, and both fields served it as current; 853 of the 10,363 leaderboard entries were affected.
  • pnl.total and pnl change value for those wallets, or are left out until Polymarket reports them.
  • The trader response’s data_quality adds a leaderboard_pnl group, dated by when Polymarket last reported the wallet. The sync group no longer covers pnl.total.
  • A trader read without a current observation asks Polymarket for one, so the field returns on a later read.
Backward compatible for field names and types; both fields were already optional. Breaking for clients that assumed pnl.total is present whenever pnl.net_total is, or that require data_quality.status to be fresh: a wallet without a current observation now reports partial.What to change: Treat pnl.total and the leaderboard pnl as optional. Use pnl.net_total for a wallet’s total, and match data_quality groups by name, ignoring unknown ones.
Pick of the Day expands its public market coverage
GET /api/v1/pick-of-the-day can now include selections from more markets.Before this change, some of those markets were never considered for a pick. Every publication check still applies, and 15 is the daily maximum, not a promised count. The private scanner feed is unchanged.Backward compatible. Request and response fields are unchanged. Already selected and historical picks keep the rules they were selected under.What to change: Nothing.
Pick of the Day expands public and private market coverage
GET /api/v1/pick-of-the-day and the private scanner feed can now include selections from more markets.Before this change, fewer markets were covered. The response still does not promise a pick count, and 15 is the daily maximum at this release.Backward compatible. Request and response fields are unchanged. Already selected and historical picks keep the rules they were selected under.What to change: Nothing.
Market snapshot volume_24h_usd now carries Polymarket's 24-hour volume, with its read time
GET /api/v1/market/{condition_id}/snapshot now fills liquidity.volume_24h_usd with Polymarket’s 24-hour volume for open markets, and adds liquidity.volume_24h_as_of, the time 0xinsider read that figure.Before this change, liquidity.volume_24h_usd was null for every market, and the field description said so.
  • liquidity.volume_24h_usd counts the shares takers bought in the 24 hours before volume_24h_as_of, each at its $1 settlement value. It is a share count, not cash, like liquidity.volume_usd.
  • It stays null when Polymarket does not report one, which it does not for closed markets.
  • liquidity.volume_24h_as_of is an ISO 8601 time, null exactly when volume_24h_usd is.
Backward compatible. liquidity.volume_24h_as_of is a new field. liquidity.volume_24h_usd keeps its name and type and now carries a number where it was always null.What to change: Nothing required. Read volume_24h_usd for a market’s recent activity, and use volume_24h_as_of to judge how current it is.
Positions drop every position on a market that has resolved
GET /api/v1/positions now returns positions on open markets only. A position leaves the feed when Polymarket resolves its market, on every read: the default feed, category, min_grade, condition_id, and wallet.Before this change, the feed also listed positions on resolved markets, often at their last price before resolution. Many of them had already been redeemed or sold. On October 9, 2026, 706 of the 2,000 largest rows were on resolved markets.
  • A condition_id read of a resolved market now returns an empty list.
  • A wallet read now returns the wallet’s positions on open markets only, so a wallet whose markets have all resolved returns an empty list.
  • A void market, settled at 50/50, counts as resolved.
Backward compatible. No field, parameter, or type changes. Fewer rows come back.What to change: Nothing, unless you read resolved positions from this route. For a wallet’s settled results, use its trader export.
Position timeline returns fills from July 17, 2026 on; older wrong-side fills are deleted
GET /api/v1/trader/{address}/position-timeline and GET /api/v1/traders/{trader}/position-timeline now return fills from July 17, 2026 on. Every returned fill is the wallet’s own trade.Before this change, the timelines also returned fills from December 12, 2022 to April 28, 2026. A retired ingester recorded those fills with the other party’s side, so each showed the opposite action, or the other outcome_side at 1 minus the price. They were deleted on October 9, 2026, and the warning about them is gone from the action description.Breaking for clients that read timeline fills before July 17, 2026: those fills are no longer returned, and running_amount and running_avg_price no longer include them. No field changes.What to change: Drop cached timeline fills dated before July 17, 2026, and recompute any total built from them.
copy_score's loss penalty compares the largest loss with capital deployed
quant_metrics.copy_score on GET /api/v1/trader/{address} and POST /api/v1/traders/batch now subtracts its 10-point loss penalty only when the wallet’s largest loss on one settled market is more than 30% of the capital it deployed across all its positions.Before this change, the penalty compared that loss with the wallet’s lifetime profit or loss. A wallet whose lifetime result was near zero or negative crossed the 30% line almost every time: on October 9, 2026, 126,113 of 200,447 wallets carried the penalty, against 13,475 under the new rule. 112,823 wallets gain up to 10 points, and 185 lose up to 10.The copy_score description in the OpenAPI document and the SDK types states the new rule. When the recorded loss on one market is larger than all the capital the wallet deployed, the inputs disagree and no loss penalty applies.Backward compatible. No field, type, or range changes. Each wallet’s score moves to the new rule the next time its metrics are computed, within 6 hours of the release.What to change: Nothing. If you stored copy_score values, do not compare scores from before this change with later ones.
Market snapshot and explore volume fields now state their unit and that one is always null
The OpenAPI document and SDK types now describe liquidity.volume_usd and liquidity.volume_24h_usd on GET /api/v1/market/{condition_id}/snapshot, and volume and rep_volume on GET /api/v1/markets/explore. The values do not change.Before this change, those four fields had no description, and volume_usd and volume_24h_usd read as dollar amounts.
  • liquidity.volume_usd, volume, and rep_volume are Polymarket’s volume figure for the market, as last stored: the total shares bought by takers, each counted at its $1 settlement value. They are share counts, not cash; 100 shares bought at $0.40 add 100, not 40. A stored figure can lag Polymarket’s current one.
  • rep_volume is the volume of the group’s highest-volume market, markets[0].
  • liquidity.volume_24h_usd is always null. 0xinsider does not store a 24-hour volume.
Backward compatible. No field name, type, or value changes.What to change: If you showed volume_usd, volume, or rep_volume as dollars traded, label them as Polymarket’s volume figure in shares. Stop reading volume_24h_usd; it never carries a value.
Pre-game volume, timeline action, and positions win_rate docs match the served values
The OpenAPI document and SDK types now describe volume on GET /api/v1/sports/pre-game-sides, action on GET /api/v1/trader/{address}/position-timeline, and trader.win_rate on GET /api/v1/positions as the values the API already returns.Before this change, those three descriptions did not match the served values:
  • volume on pre-game sides and on GET /api/v1/sports/pre-game-side-observations was described as USD. It is Polymarket’s traded-volume figure: cumulative taker volume in shares, each counted at its $1 settlement value. It is not the cash that changed hands; 100 shares bought at $0.40 add 100, not 40.
  • action on the position timeline was described as the taker’s side. It is the wallet’s own side of the fill. Fills dated before April 29, 2026 come from a retired ingester that recorded the other party’s side, so treat them as unreliable until they are removed.
  • trader.win_rate on positions was described as a percentage from 0 to 100. It is a ratio from 0 to 1, the same scale as the trader profile.
Backward compatible. No value, field, or type changes.What to change: If you showed volume as dollars traded, label it as Polymarket’s volume figure in shares. If you showed trader.win_rate as a percentage, multiply it by 100 first. If you rely on timeline fills dated before April 29, 2026, do not trust their side.
The games catalog adds K League 1 coverage
GET /api/v1/games now includes K League 1 games in coverage.leagues as kor, under sport=Soccer. Use sport=Soccer&league=kor to list them, then GET /api/v1/games/{event_slug} for one game’s linked markets.Before this change, K League 1 had no dedicated scope in the games catalog.Coverage follows Polymarket’s published games. K League 2 is a separate league and is not included in this scope. Live status and scores follow the provider; a passed kickoff does not make a game live.Backward compatible. The league coverage is additive. Existing request parameters and response fields are unchanged.What to change: Nothing. Use league=kor when you want only K League 1 games.
Games and pre-game observations add EuroLeague coverage
GET /api/v1/games now includes EuroLeague games in coverage.leagues as euroleague, under sport=Basketball. Use sport=Basketball&league=euroleague to list them, then GET /api/v1/games/{event_slug} for one game’s linked markets.Before this change, EuroLeague had no dedicated scope in the games catalog or the upcoming basketball supply for pre-game observations.
  • GET /api/v1/sports/pre-game-side-observations includes upcoming EuroLeague games in its basketball supply.
  • funnel.sports[].board_upcoming_unavailable_scopes can contain euroleague-basketball when that upcoming source is unavailable. The OpenAPI enum and generated SDK types include the value.
  • EuroLeague live status and scores still follow the provider. The upcoming scope does not infer that a game is live from its kickoff time.
Backward compatible. Coverage and the unavailable-scope value are additive.What to change: Nothing unless you validate the unavailable-scope values against a fixed list; add euroleague-basketball. Use league=euroleague when you want only EuroLeague games.
OpenAPI nullable enums accept the null values the API already returns
GET /api/v1/large-trades and other responses with nullable enum fields now have OpenAPI 3.1 declarations that accept the null values those responses already return.Before this change, the schemas used nullable: true while their type or enum still excluded null. Standard response validators could reject valid API responses.
  • Large-trade suspicion_track and trader.grade_at_trade allow null.
  • Already-nullable platform fields in market search, exploration, flow, and reports allow null.
  • Already-nullable grade, pre-game side, webhook reason and outcome, and account recovery fields allow null.
  • The unavailable pick response keeps supersedes_pick_id restricted to null.
Backward compatible. API payloads, request parameters, and non-null enum values stay the same. Current SDK types already include these null values.What to change: Refresh your OpenAPI document or regenerate response validators if you validate API responses. Existing API calls and SDK types need no changes.
Combo fills and details avoid repeated lookups when a response is not cached
GET /api/v1/combos/fills and GET /api/v1/combos/{condition_id} now avoid repeated lookups when building a response that is not cached.Before this change, fill selection repeated some checks for the same combo, and detail requests read the same legs more than once.Responses keep the same fields, exact amounts, result rules, filters, pagination, access requirements, and cache freshness. Database or cache service pauses can still delay a response; this update does not establish that every request completes within 250 milliseconds.Backward compatible. No response field or request parameter changes.What to change: Nothing.
The REST API adds combo fills, a live-combo count, and individual combo details
GET /api/v1/combos/fills, GET /api/v1/combos/summary, and GET /api/v1/combos/{condition_id} now return recorded Polymarket combo activity with paid API access.Before this change, the external REST API had no routes for combos.
  • The fill list returns wallets, legs, execution amounts, and combo results. It accepts result, leg count, stake, multiplier, grade, and sport filters, with newest-first or ranked pagination.
  • Shares, collateral, fees, and execution prices retain exact decimal strings. The list excludes fills priced above 0.95 and returns full rows without the website’s free delay.
  • The summary returns only the stored live-combo count and its computed_at. An unavailable count is null, not 0.
  • One combo’s detail returns its legs, totals, latest 100 taker fills, lifecycle amounts when recorded, and data coverage. Combo results describe the YES conjunction, not a wallet’s realized P&L.
Backward compatible. These routes are additive, and existing responses are unchanged.What to change: Nothing. Use the new routes when you need combo data.
potd-trader v0.4.1 sets up Kalshi execution with one interactive command
potd-trader v0.4.1 adds a one-command installer and kalshi setup wizard that asks for credentials, a private key file, spending limits, and reviewed contract mappings in your terminal.Before this change, Kalshi setup required a release checkout, manual configuration edits, and separate commands for account checks, mapping, and dry runs.
  • The installer keeps Python and the trader isolated from your global installation.
  • New setups default to demo with orders stopped. Existing stopped setups retain their account, mappings, and ledger.
  • The wizard checks the account and picks, guides the existing contract review, and runs a dry run. Enabling orders still requires your environment’s explicit confirmation.
Backward compatible. Existing commands, mappings, spending limits, and execution guards remain available.What to change: Run the setup command instead of editing configuration by hand. Stop existing watchers before upgrading.
potd-trader v0.4.0 adds demo-first Kalshi execution with reviewed contract mappings
potd-trader v0.4.0 adds a kalshi command group for separate demo and production setups, manually reviewed contract mappings, dry runs, order controls, and reconciliation.Before this change, the standalone trader submitted orders only on Polymarket. The Pick of the Day signal and API remain Polymarket-backed.
  • kalshi init creates a separate configuration with demo mode and orders disabled.
  • kalshi map requires review of both contracts and your own Kalshi price ceiling. Source authorization and slippage limits remain additional price guards; Polymarket modeled returns are not transferred.
  • Kalshi orders use whole contracts and immediate-or-cancel submission. Daily reservations include worst-case fees; uncertain submissions stay blocked until reconciled.
  • Changed contract PDFs or reported target positions or resting orders prevent new submissions. Use a dedicated account with no concurrent manual or other-tool trading; provider account reads can lag.
Backward compatible. The existing Polymarket commands remain available.What to change: Install v0.4.0 and follow the Kalshi guide to create a separate setup. Existing Polymarket users need no configuration changes.
Pre-game sides includes holdings across linked events for the same game
GET /api/v1/sports/pre-game-sides and its deprecated alias GET /api/v1/sports-edge-signals now include positions across a game’s provider-owned parent and companion events when calculating directional_confidence, one_way_holder_count, hedged_holder_count, and one_way_graded_usd.Before this change, separate event slugs could omit opposing or unresolved holdings in the same game and overstate how one-way a wallet’s positions were.Backward compatible. Field names, types, and meanings are unchanged.What to change: Nothing.
Pre-game sides recognizes team direction from named spread outcomes
GET /api/v1/sports/pre-game-sides and its deprecated alias GET /api/v1/sports-edge-signals now identify the team a spread position backs when both outcome labels name distinct teams. directional_confidence, one_way_holder_count, and hedged_holder_count reflect those positions across the game’s markets.Before this change, named spread outcomes were ignored. A position could leave directional_confidence as null, or make a wallet holding the same team’s moneyline and spread appear to back different teams.Generic Yes/No answers and unresolved outcomes remain unclassified. Position freshness checks and the safeguards for wallets holding both outcomes still apply.Backward compatible. Field names, types, and meanings are unchanged.What to change: Nothing.
Pick of the Day removes editorial_note from the API, SDK, and MCP responses
GET /api/v1/pick-of-the-day, the TypeScript SDK’s PickOfTheDay type, and the MCP get_pick_of_the_day tool no longer expose editorial_note.Before this change, a pick could include an editorial note. The field and its website display have been removed.Breaking for clients that read editorial_note.What to change: Remove editorial_note from your response models and displays. Do not require the field in stored responses or future reads.
Trader export markets describe a settled position by what it bought
The markets rows in a JSON or NDJSON file from POST /api/v1/trader/{address}/export now describe a settled position by the shares it bought, not by the shares left after the market settled. A new field, settled_side, names the outcome a settled position took: yes, no, or both when it bought both outcomes. It is null on an open row.Shares left after settlement cannot tell you a side. A wallet redeems its winning shares and keeps its losing ones, so a settled row usually shows 0 and 0, or only the losing outcome.
  • avg_price on a settled position that bought both outcomes is now null. Before this change it was the Yes entry price, or the entry price of the outcome with shares left, which is usually the one that lost.
  • up_bought and dn_bought on a settled row are now the shares each outcome bought: that outcome’s cost divided by its average entry price. They are null when a position bought both outcomes and its cost per outcome is not recorded. Before this change they repeated up_shares and dn_shares, which are 0 and 0 on nearly every settled row.
  • Open rows do not change.
Backward compatible. settled_side is a new field, and no field is removed or renamed. avg_price, up_bought, and dn_bought were already nullable.What to change: Read settled_side to tell a position on both outcomes from a one-sided one. If you read up_bought and dn_bought on settled rows, expect real share counts where you saw zeros.
Positions trader.pnl and trending all_time_pnl_usd carry the profile's total P&L
trader.pnl on GET /api/v1/positions and all_time_pnl_usd on GET /api/v1/leaderboard/trending now carry the wallet’s total P&L as its 0xinsider profile shows it: Polymarket’s position P&L, fees included, plus maker and taker rebates. It is the same figure GET /api/v1/trader/{address} returns as pnl.net_total. The remote MCP tools get_positions and get_trending_wallets return the same values.Before this change, both fields carried pnl.total, Polymarket’s all-time leaderboard figure, which can differ from the profile’s total by a wide margin and even in sign.
  • Either field is omitted when Polymarket’s figure for the wallet is not available. The leaderboard figure is never sent in its place.
  • Neither field affects which rows a page holds or their order. GET /api/v1/positions still orders by current_value_usd, and the trending list still follows Polymarket’s order.
  • A trending list built before this change keeps its old all_time_pnl_usd until it is rebuilt. A request that finds the list at least 2 minutes old starts a rebuild.
Backward compatible. No field is added, removed or retyped. Both fields change value for most wallets.What to change: Nothing, if you show these fields as the wallet’s total P&L. If you compared them with pnl.total from the trader endpoint, compare them with pnl.net_total instead.
category_strengths counts markets a wallet bought on both sides
category_strengths on GET /api/v1/trader/{address}?expand=categories and on POST /api/v1/traders/batch now counts every settled position of $20 or more in each category, including a market the wallet bought on both sides. n_markets, wins, losses, win_rate, total_pnl and its alias scaled_total_pnl change for a wallet that holds such markets. rank and total_in_category move with them, and a wallet can enter a category it was below the 5-market floor in.Before this change, a position counted only when it had one side with an entry price between 0 and 1, so a market bought on both sides was left out, and its profit or loss and its result with it. On a 0.2% sample of settled positions of $20 or more on October 7, 33.8% were bought on both sides.The edge over the price paid on the category leaderboards still scores only positions with one priced side: a market bought on both sides has no single side to score.Backward compatible. The response shape is unchanged. Values move as each wallet’s categories are recomputed over the following days.What to change: Nothing. If you store category_strengths values, re-read them once the recompute has reached your wallets.
Pick of the Day selections can become available earlier
GET /api/v1/pick-of-the-day can now publish automatic picks earlier in the day. Before this change, automatic picks appeared closer to kickoff. A published pick keeps its market, side, and frozen price.Read the returned release_at rather than calculating it from kickoff. retry_at and Retry-After on a 404 with pick_not_released still give the next time to ask.Backward compatible. Response shapes do not change; picks can appear earlier in the day.What to change: Nothing, if you follow retry_at. If you schedule reads from kickoff times, read earlier: a pick can be available hours before its game.
Trader adds pnl.net_total, the total P&L the 0xinsider profile shows
GET /api/v1/trader/{address} and POST /api/v1/traders/batch now return pnl.net_total, the wallet’s total P&L as its 0xinsider profile shows it. It is Polymarket’s position P&L, fees included, plus maker and taker rebates, cut to whole cents, and it is omitted when Polymarket’s figure is not available. With expand=trust, trust.net_total_pnl describes its source, and the remote MCP tools get_trader and batch_get_traders return the same field.Before this change, the only total was pnl.total, Polymarket’s all-time leaderboard figure. It is not realized plus unrealized P&L, and on October 7, 2026 it differed from the profile’s total by more than $1 for 7,851 of 8,449 ranked wallets.
  • pnl.total keeps its value and is now documented as Polymarket’s leaderboard figure. pnl on GET /api/v1/leaderboard is the same figure, also unchanged.
  • The Total P&L line of GET /api/v1/trader/{address}/context.md now reads pnl.net_total, so it matches the profile and the JSON body.
  • trader.pnl on GET /api/v1/large-positions now carries the same total as pnl.net_total. It was documented as realized P&L but carried the leaderboard figure, and it is omitted when the wallet has no total.
  • The sync group in data_quality now covers pnl.net_total.
Backward compatible for pnl.net_total and every unchanged field. trader.pnl on large positions changes value for most wallets.What to change: Read pnl.net_total wherever you show a wallet’s total P&L. If you compared large-positions trader.pnl with pnl.total, compare it with pnl.net_total.
Large-trade market_volume_share now divides shares by shares
GET /api/v1/large-trades, GET /api/v1/large-trades/history, their /api/v1/whale-trades aliases, and the MCP get_large_trades and get_large_trades_history tools now compute market_volume_share as the trade’s share count over the shares its market has traded. Polymarket records market volume in shares, so both sides of the ratio are now in the same unit.Before this change, the numerator was size_usd, so every value read the true share multiplied by the trade’s price. Over the 30 days to October 7 the old value was a median 1.74 times too small, and about 4.3 times too small for trades priced under 30 cents. sort=market_volume_share ranked favourites above longshots of the same size: half of its top 50 changes.
  • Every published value is larger, by a factor of 1 / price. The field still reads between 0 and 1, and its name and type are unchanged.
  • min_market_volume_share filters and sort=market_volume_share ranks by the corrected value, so the same threshold now returns more trades.
  • The share is withheld when the recorded market volume is smaller than the trade’s share count. Over those 30 days this withheld one trade the old rule had published.
  • A sort=market_volume_share cursor minted before this change continues against the new values, so a ranking paged across the change can skip trades.
Breaking for clients that compare market_volume_share with stored values or thresholds tuned to the old numbers. The response shape is unchanged.What to change: Re-read any stored market_volume_share values, and restart a sort=market_volume_share ranking from its first page. A min_market_volume_share threshold tuned to the old values now admits more trades; raise it if you want pages of a similar size.
OpenAPI quota text and examples state the 500,000 Pro and 2,000,000 Max allowances
The OpenAPI document now states the monthly quota the API enforces: 500,000 requests per UTC month on Pro and 2,000,000 on Max, with pay as you go up to 4 times the plan’s allowance. The @0xinsider/mcp 2.14.4 package README states the same allowances, and 2.14.4 requires @modelcontextprotocol/sdk 1.32.1 or later, past advisory GHSA-6qxp-vccf-f47h.Before this change, parts of the document still described the allowance from before October 1, 2026:
  • The 429 descriptions of GET /api/v1/sports/pre-game-sides, GET /api/v1/sports/pre-game-side-observations, GET /api/v1/pick-of-the-day/ledger/{pick_id}, POST /api/v1/webhooks/{id}/verification-attempts, and GET /api/v1/webhooks/{id}/verification-attempts/{attempt_id} said Pro includes 250,000 requests, with a 1,000,000 pay-as-you-go ceiling.
  • X-Monthly-Quota-Limit and monthly_quota.limit described only Pro’s allowance and showed 250000. They now name both plans, and the examples show 500000.
  • monthly_quota.ceiling said limit, or 1,000,000 with pay as you go on. It now says 4 times limit.
  • The monthly_quota_exceeded error reason now says the account used its plan’s included requests, not the requests Pro includes.
The API’s behavior, fields, and headers are unchanged.Backward compatible.What to change: Nothing. If you sized a client from the old text, read X-Monthly-Quota-Limit or monthly_quota.limit instead of a fixed number.
Pick of the Day groups Wimbledon by ATP/WTA and all cricket as Cricket
GET /api/v1/pick-of-the-day and the archive now return ATP or WTA in display_category for tennis with a known tour, including Wimbledon and doubles. Men’s and women’s cricket competitions return Cricket. Tennis with an unknown tour remains Tennis.Before this change, tennis could carry a tournament label such as Wimbledon, and cricket could carry a competition label such as The Hundred Women.Historical display labels are corrected too. The response shape, category, pick identities, results, prices, and returns remain unchanged.Breaking for clients that match the previous tournament or cricket competition labels.What to change: Accept ATP, WTA, and Cricket, and refresh stored historical display_category values before rebuilding grouped statistics. Keep using category for the canonical sport bucket.
The MCP server card is also served at /.well-known/mcp.json
GET https://0xinsider.com/.well-known/mcp.json now returns the MCP server card, the same JSON document as GET https://0xinsider.com/.well-known/mcp. Some MCP discovery tools and site audits look for the card only at the .json path, where they received an error before this change./.well-known/mcp is unchanged and remains the canonical address. The MCP transport (POST) stays on /.well-known/mcp and https://api.0xinsider.com/api/v1/mcp.Backward compatible.What to change: Nothing.
Trader grade-at observations report model_version grading, not grading-v4
GET /api/v1/trader/{address}/grade-at now returns observation.model_version as grading where it returned grading-v4. The field names the model family that wrote the grade, and 0xinsider has one wallet grading model, so the version suffix is gone. Every stored observation reads the new value, including the ones recorded before this change.The grade, the timestamps, model_build_sha, and every other field are unchanged. null still means the model is unknown.Breaking for clients that compare model_version with the exact string grading-v4.What to change: Accept grading. To tell builds of the model apart, read observation.model_build_sha.
Pick of the Day updates daily availability and retry guidance
GET /api/v1/pick-of-the-day changes when automatic picks first become available for a New York date. Its retry fields now name the next available read time.Before this change, the next read time could be earlier than the day’s first available automatic pick.
  • Before a day’s first available pick, and after a skipped day, schedule your next read from the 404 pick_not_released response’s error.retry_at or Retry-After.
  • Read each pick’s actual publication time from published_at.
  • The response fields, release_at, and the 404 body shape are unchanged.
Backward compatible.What to change: Nothing. If you poll, keep scheduling the next read from error.retry_at or Retry-After.
Pick of the Day moves automatic publication closer to kickoff
GET /api/v1/pick-of-the-day changes automatic publication timing so picks appear closer to their games. Picks still arrive throughout the day, up to the release’s limit of 15.Before this change, automatic picks could appear earlier in the day.
  • The response fields, release_at, and the 404 pick_not_released response are unchanged.
  • A scheduled pick still waits for its returned release_at.
Backward compatible.What to change: Nothing. If you poll, keep scheduling the next read from error.retry_at or Retry-After.
Pick of the Day pick_rank can reach 20 after a cancelled pick; picks stay at 15
GET /api/v1/pick-of-the-day can now return a pick_rank above 15 on a day with a withdrawn pick. A pick withdrawn because its game was cancelled keeps its rank but no longer uses one of the day’s 15 picks, so the next pick takes the next free rank, up to 20.Before this change a cancelled pick held one of the 15 slots, so that day ended with 14 picks.
  • pick_rank now runs from 1 to 20 in picks, scheduled_picks, locked_picks, proof_pending_picks, the archive, and the ledger, and the OpenAPI document and the Pick of the Day MCP tool’s output schema say so.
  • pick_count is still at most 15, and a day still carries at most 15 picks.
  • pick_rank is deprecated. Use pick_id for identity and publication_order for order.
Backward compatible for clients that read picks as a list.What to change: If you validate pick_rank against a maximum of 15, or index a fixed 15-slot array by rank, raise the bound to 20 or key by pick_id.
Live-score source_revision values jump to millisecond scale and stay increasing
GET /api/v1/market/{condition_id}/snapshot now sends sports.live_score.source_revision and sports.live_score.tennis_points.source_revision as 13-digit integers, about 1,790,000,000,000 today. Each new revision is still greater than every earlier one for the same group, including after a restart of our cache.Before this change both values were small counters, about 2,000,000 and 50,000. A cache restart could move them backwards for up to 15 minutes, and a client that kept only strictly newer revisions froze the live score for that time.
  • The values are still integers that order updates. They are not timestamps; do not read them as a time.
  • Every value fits in a JavaScript safe integer and in a signed 64-bit integer. It does not fit in a 32-bit integer.
  • The first update after the change jumps from the small counter to the large value. A “newer than” check accepts it.
Backward compatible for clients that compare revisions or store them as 64-bit integers or JavaScript numbers.What to change: If you store source_revision in a 32-bit integer column or variable, widen it to 64 bits. Nothing else.
MCP 2.14.3 cancels HTTP work and bounds documentation resource reads
@0xinsider/mcp 2.14.3 now forwards MCP request cancellation to every tool and resource HTTP read. Documentation resources also have a 15-second deadline covering headers and the complete response body.Before this change, cancelled API reads continued until their existing deadline, and documentation reads had no deadline. Caller cancellation now has the local error code request_cancelled; the server’s own API deadline retains request_timeout.Cancelling a request stops the local HTTP read. It does not roll back a POST that already committed or guarantee that the remote server stopped its work. Tool names, arguments, results, and automatic retry behavior are unchanged.Backward compatible.What to change: Upgrade the local package to 2.14.3 once it is published. No MCP configuration changes are required.
TypeScript SDK 0.18.0 types empty picks and withheld identity fields
The generated declarations in @0xinsider/sdk 0.18.0 now describe the current API contract. API response bodies and SDK request behavior are unchanged by this release.Before this change, the published SDK declarations omitted these response cases:
  • getPickOfTheDay can return state: "none" with no entitled picks. Narrow on state before reading fields from a full pick.
  • Archive and uncommitted-ledger entries can omit matchup and category. Check whether each field is present before rendering it.
  • Sealed ledger entries withhold kickoff. Read the recorded kickoff from an opened entry when it becomes available.
  • entry_authorization.policy_version supports an additional opaque value. Validate it against the versions supported by your client while retaining your authorization checks.
  • MarketSnapshot.sports.live_score.tennis_points, when present, follows the named TennisPoints shape. Custom response objects must use that shape.
The SDK also exports PickOfTheDayNoEntitledPicks, TennisPoints, and TennisRanking by name.Breaking for TypeScript clients that depend on the previous narrower declarations.What to change: Update the affected narrowing, presence checks, and response types before upgrading to 0.18.0. Existing runtime requests remain valid.
TypeScript SDK optional fields explicitly permit existing undefined values
The TypeScript SDK, @0xinsider/sdk, now explicitly permits undefined in optional paging progress, parsed stream-frame, and data freshness fields that already return it. This makes the declarations usable with TypeScript’s exactOptionalPropertyTypes option.Before this change, those declarations used optional properties without explicitly describing their existing undefined values. Callers with the stricter compiler option could therefore reject otherwise valid SDK values.Return values and API response bodies retain their existing shapes. The SDK also checks indexed access and control flow during development; missing optional request fields are omitted before calling Fetch.Backward compatible. This adds accurate type information without changing valid requests or returned data.What to change: Nothing. Enable exactOptionalPropertyTypes in your own project when you are ready to check absent properties separately from explicit undefined.
Referral-only paid API and feed access ends when the earned grant ends
Paid operations in the REST API, MCP, and the live event feed now require an unexpired referral grant when referral rewards are the account’s only source of Pro access. A refund removes the unearned portion of that grant. Independently paid subscriptions and separately authorized complimentary access retain their access.Before this change, an expired referral grant could leave a never-paying account authorized for Pro indefinitely. Already awarded referral access could also survive a refund of the qualifying payment.The response schema and authentication headers are unchanged. Once temporary paid access ends, paid API operations return the existing subscription-required refusal, and an open paid feed disconnects on its normal authorization recheck.Breaking for clients that depended on referral access continuing beyond its earned period.What to change: Handle the subscription-required response by prompting the account owner to subscribe. Reconnect paid feeds only after the account has valid paid access.
Soccer games identify home, draw, and away markets
GET /api/v1/games and GET /api/v1/games/{event_slug} now identify each soccer result market and report when the game offers a draw.For a soccer game with home-win, draw, and away-win markets:
  • markets[].side identifies each market as home, draw, or away.
  • draw_offered is true when the game offers a draw market.
Before this change, these soccer markets omitted side, and the game reported draw_offered: false even when a draw market was present. The SDK’s listGames and getGame methods and MCP’s list_games and get_game tools return the same corrected fields.Backward compatible. Existing optional fields now carry the classified values; no field or type migration is required.What to change: Nothing. Use markets[].side and draw_offered to identify result markets instead of guessing from their labels.
Pick of the Day archive excludes withdrawn picks and their statistics
GET /api/v1/pick-of-the-day/archive now excludes withdrawn recommendations from picks, days, hit_rate, and the cumulative series. A later market settlement does not return a withdrawn pick to the archive.Before this change, a withdrawn released pick remained in the archive and could contribute to its statistics after settlement. Withdrawn picks are also excluded from current and dated recommendations.The public ledger keeps every published commitment under its original pick_id. Its identity and proof bytes remain unchanged, and market settlement still determines the recorded result. Request and response fields are unchanged.Breaking for clients that use the archive as a complete list of published commitments.What to change: Refresh cached archive responses and use the public ledger when you need every published commitment. No field or type migration is required.
Pick of the Day excludes cancelled games from active recommendations
GET /api/v1/pick-of-the-day now excludes a pending pick from active recommendations when its game is explicitly cancelled. New selections also check the provider’s game status before publication.Before this change, a cancelled game could be selected or remain in the current day’s recommendations.The archive and ledger retain the released pick’s identity and publication record. Market settlement still determines its recorded result.Backward compatible. Request and response fields are unchanged. The endpoint can return fewer picks or the existing 404 with error.reason: "pick_not_released" when no active pick remains.What to change: Nothing. Keep handling an empty day with Retry-After or error.retry_at, and store each pick_id rather than assuming a fixed pick count.