Skip to main content
These are the API changelog entries from October 21 to 24, 2026, newest first. The newest changes are on the API changelog.
Category strengths and the export's price edge cover sports and esports markets only
category_strengths on GET /api/v1/trader/{address} with expand=categories now holds sports and esports categories only. A category outside them, such as Politics or Crypto, is left out. MCP tools and SDK calls that read this route return the same keys.In the dataset export file, trader.price_edge is now the wallet’s edge over the price it paid on sports and esports markets, checked against its sports and esports win rate. export_metadata.scope_note says so.Before this change, category_strengths held every category the wallet traded, and price_edge counted every market. 0xinsider no longer updates categories outside sports and esports, so their ranks would have gone stale.
  • The values for a sports or esports category are unchanged.
  • A wallet’s price_edge can change. A wallet with fewer than 30 priced sports and esports markets now has status too_few_markets.
  • Trader category records already returned sports and esports categories only.
Backward compatible for clients that read category_strengths as a map of the keys it holds.What to change: Do not expect a category_strengths key for a category outside sports and esports.
Trader category_records list sports and esports categories only
category_records on GET /api/v1/trader/{address} with expand=categories now holds sports and esports categories only. A category outside them, such as Politics or Crypto, is left out. Batch traders, Trader context, the MCP get_trader tool, and SDK calls that read these routes return the same records.Before this change, category_records held a record for every category the wallet traded. On October 25, 2026, one wallet’s 106 records held 94 outside sports and esports.
  • A sports or esports record is unchanged, and so is category_skill_model.
  • Trader category records and category_strengths already returned sports and esports categories only.
Backward compatible for clients that read category_records as a list of the records it holds.What to change: Do not expect a record for a category outside sports and esports.
Large trade counterparties read ExchangeV3 fills, as exchange_family exchange_v3
GET /api/v1/large-trades/{id} and its counterparty executions now return the counterparties of a large trade in a Polymarket Protocol V2 binary or neg-risk market. Polymarket settles those markets on its ExchangeV3 contract, so exchange_family on each execution has a third value, exchange_v3.Before this change, 0xinsider never read the Polygon receipt of such a trade. Its counterparty_analysis stayed unavailable with unavailable_reason evaluation_not_seeded.
  • ctf_v2 and neg_risk_ctf_v2 executions are unchanged.
  • A Protocol V2 combinatorial fill is not a large trade, so it never has an execution.
  • The MCP tools that return these objects and the TypeScript SDK’s CounterpartyExecution type name the new value.
Backward compatible. The value is additive. A client that rejects an unknown enum value will reject these executions.What to change: Accept exchange_v3 wherever you read exchange_family, or treat any value you do not know as another exchange.
Market holders limits each account's uncached reads to 6 a minute
GET /api/v1/market/{condition_id}/holders now limits how many uncached markets each account can request. A request for a market whose holder list is not cached makes 0xinsider scan Polymarket, and each account may start 6 of these scans per minute, with bursts of up to 400. A request over that share returns 429 with error.code rate_limited, the new error.reason cold_read_limited, Retry-After, and error.retry_at.Before this change, an account could start as many scans as its per-minute request allowance allowed. On October 24, 2026, one account’s scans of uncached markets slowed holder reads for other callers.
  • Cached markets do not count and still answer, including a market that another caller has just read.
  • The share is per account, across all of its keys, like the per-minute allowance.
  • No scan runs for a refused request.
  • On the 24 hours the share was sized on, no other account reached it.
Backward compatible. This endpoint already documented 429 rate_limited with Retry-After, and the new reason is additive.What to change: If you sweep many markets, wait for Retry-After on a 429 with reason cold_read_limited, or space uncached requests 10 seconds apart once your burst is spent.
Explore keeps a market's 24-hour change while Polymarket's price history runs behind
GET /api/v1/markets/explore now keeps change_pct_24h and no_change_pct_24h for an open market while Polymarket’s minute price history is up to 10 minutes behind. Polymarket sometimes stops recording minute prices for every market at once, for 2 to 14 minutes. In the 24 hours to 18:00 UTC on October 24, 2026, that was 9.6% of the time.Before this change, both fields became null for every open market once the newest recorded minute was more than 2 minutes old.
  • During such a gap, the change covers the 24 hours to Polymarket’s latest recorded minute, not to the time of your request. The last point of price_points and no_price_points is that minute.
  • A market whose price history stopped before the others, such as a resolved market, still sends null.
  • When the history is more than 10 minutes behind, both fields are null, as before.
Backward compatible. The fields and their types are unchanged. They are null less often.What to change: Nothing. To show how current a change is, read the timestamp of the last point in price_points.
A Challenger qualifying match's competition_label ends in ', Qualification'
GET /api/v1/pick-of-the-day now sends sports_context.competition_label for an ATP Challenger qualifying match with , Qualification at the end, for example Seoul, Qualification. Polymarket already labels ATP 250, ATP 500, and WTA qualifying this way, such as Erste Bank Open, Qualification.Before this change, a Challenger qualifying match had the same label as its main draw, for example Seoul. Polymarket marks these matches only in its eventMetadata.tennisFixtureSource field, with the value optic-challenger-qualifying.
  • A label that already names a qualifying draw is unchanged.
  • Main-draw labels are unchanged.
Backward compatible. The field and its type are unchanged.What to change: If you group tennis picks by competition_label, treat a label that ends in , Qualification as the qualifying draw of the tournament named before it.
A national team's logo is now its official national flag as a same-origin SVG
GET /api/v1/pick-of-the-day now sends a national team’s sports_context team logo as its official national flag: a same-origin path such as /api/sports/team-logos/unl/esp.svg?v=e6ce1922eba61c4a. This covers 1,326 national-team rows across 41 competitions, for men, women, and youth sides.Before this change, those teams carried Polymarket’s raster flag or federation crest URL.
  • The flag is an SVG at the flag’s own aspect ratio, so draw it contained in a square slot, not cropped.
  • Rows that are not exactly one country keep their previous artwork. These include Chinese Taipei, Northern Ireland, overseas territories, and bracket placeholders.
  • A URL that a client cached before this change still serves the image it named.
Backward compatible. The field already carried same-origin paths for club crests.What to change: Nothing, if you already resolve a relative logo against the API origin. Otherwise, resolve it against https://api.0xinsider.com.
Team names in Pick of the Day sports_context use plain spaces
GET /api/v1/pick-of-the-day now sends label and full_name on each team in sports_context with ordinary spaces between words. Every Unicode space character, such as the no-break space U+00A0, becomes U+0020.Before this change the names kept the bytes Polymarket sends, and Polymarket sends some team names with a no-break space between words. On October 24, 2026, 2 of 33 AHL teams were sent that way: Cleveland Monsters and Grand Rapids Griffins. A no-break space makes the whole name one word, so a narrow layout broke it inside a word.The market’s own outcome labels and title are unchanged and can still hold the provider’s no-break space.Backward compatible. Only the space characters inside a few team names change.What to change: If you compare a team’s label or full_name with a market outcome label by exact string, treat any whitespace as a plain space on both sides first.
Edge Hunter observations read a sport's pre-game holders only while someone asks
GET /api/v1/edge-hunter with view=observations now reads a sport’s pre-game wider_holder holders only while a wider_holder or emerging_pile request named that sport in the last 30 minutes. A request with no category counts for every sport. The default selection and admission=most_held_48h are counted apart, and in-play reads never stop.Before this change, every snapshot read the pre-game holders of every sport, whether or not anyone asked for them.
  • After 30 minutes with no request for a sport, the first request for it returns 503 with error.reason: read_model_warming and Retry-After: 45. The retry returns the same rows as before.
  • A request with no category gets the same 503 while any sport is in that state.
  • While a sport’s holders are not read, its admitted markets count in coverage.capacity_limited_markets and not in coverage.emitted_observations.
  • The rows, fields, ordering, and departures of a sport that someone reads are unchanged.
Backward compatible. No field is added or removed. The SDK retries this 503 for you, because its Retry-After is under 60 seconds.What to change: Nothing for a client that retries read_model_warming after Retry-After. A client that reads a sport less often than every 30 minutes should expect one 503 before its first answer.
The OpenAPI document marks nullable fields the OpenAPI 3.1 way
GET /api/v1/openapi.json now marks every field that can be null the way OpenAPI 3.1 defines: "type": ["string", "null"], or a oneOf with a {"type": "null"} branch. The document already declared "openapi": "3.1.0".Before this change, 370 schemas used the OpenAPI 3.0 keyword "nullable": true, which OpenAPI 3.1 does not have. A 3.1 validator or code generator ignores that keyword, so it read those fields as never null and rejected the null the API sends. One example is the always-null supersedes_pick_id on a Pick of the Day response with no entitled picks.
  • A nullable enum now lists null as a member, for example category on Edge Hunter rows and grade on large-trade webhook payloads.
  • A nullable object reference is now "oneOf": [{"$ref": "..."}, {"type": "null"}].
  • yes_team and no_team in the Pick of the Day sports_context were declared in a form that generated clients read as never null. They are now nullable, as the API has always sent them.
  • The MCP tools’ output schemas use the same spelling.
  • The SDK source in 0xinsider/0xinsider now types PickSportsContext.yes_team and no_team as PickSportsTeam | null, and the next @0xinsider/sdk release carries it. No other SDK type changes. The published 0.31.0 is unchanged.
Backward compatible. API responses are unchanged. Only the description of which fields can be null changed, and it now matches what the API sends.What to change: If you generate a client from the document, regenerate it and handle null on the fields it now types as nullable. With @0xinsider/sdk, check yes_team and no_team for null before you read them; they can already be null today.
The neg-risk P&L correction no longer waits on markets outside sports and esports
On GET /api/v1/trader/{address}, pnl.correction now publishes once every converted neg-risk market of the wallet that has a sports or esports event is measured. pnl.correction_pending is true only while one of those markets is still being checked.Before this change, every converted market of the wallet had to be measured first, sports or not. A wallet with many converted markets outside sports and esports could stay pending for weeks, with no correction on its sports and esports P&L either.
  • A converted market with no sports or esports event is no longer measured. An earlier measurement of one still counts in amount and markets_measured.
  • The same applies to pnl_correction on leaderboard and trending wallet entries, and to the SDK’s PnlCorrection.
  • The fields, their types, and the neg_risk_conversion_v1 basis are unchanged.
Backward compatible. No field is added or removed.What to change: Nothing. Expect fewer wallets with pnl.correction_pending set. A wallet-wide amount can leave out part of the gap on markets outside sports and esports.
Export snapshot volume, gap, and coverage are null when a day has no volume
On GET /api/v1/trader/{address}/export, reconciliation.exported_activity_volume is now null when any of the wallet’s daily P&L rows has no volume. provider_activity_volume_gap and activity_volume_coverage are then null too. The export file’s summary.volume_reconciliation and the get_trader_export_snapshot MCP tool follow the same rule.Before this change, the sum skipped those days. Every day from 2026-10-23 on has no volume, so the sum was a subtotal of the earlier days, the gap read too high, and the coverage read too low.
  • A wallet with any daily P&L row from 2026-10-23 on now reads null for all three fields.
  • A wallet whose daily P&L stops before 2026-10-23 keeps its volume, and its gap and coverage whenever provider_lifetime_volume is present.
  • provider_lifetime_volume, exported_market_cost_basis, and every other field are unchanged.
Breaking for clients that read exported_activity_volume as a number. The field was typed as always present.What to change: Accept null for exported_activity_volume and read it as unknown, not zero. Treat a null gap or coverage the same way.
Holder wallet_age_days is whole days, so Pick of the Day revalidation returns 304
wallet_age_days on each holder from GET /api/v1/pick-of-the-day and GET /api/v1/market/{condition_id}/holders is now whole days since the wallet’s first trade, rounded down. A wallet that first traded 3.6 days ago reads 3.Before this change, the value was a fraction of days measured at the moment of your request, such as 250.49197916666665. It changed every second, so the Pick of the Day ETag changed on every request and If-None-Match never returned 304 Not Modified.
  • The value now changes once a day for each wallet. A Pick of the Day response keeps its ETag until the picks or their holders change.
  • is_new_wallet is unchanged. It is still true when the first trade was under 30 days ago.
  • The field is still a JSON number, and it is still present only beside the other badge fields.
Backward compatible. The type and the field set are unchanged. Only the precision changed.What to change: Nothing. If you poll the Pick of the Day with If-None-Match, you now get 304 responses between changes.
Daily P&L entries leave out total_volume from October 23, 2026
On GET /api/v1/trader/{address}/pnl, entries[].total_volume is left out for every UTC day from 2026-10-23 on. The get_trader_pnl MCP tool returns the same entries.From that day 0xinsider stores only part of a wallet’s fills on markets outside sports and esports, so it no longer knows the wallet’s total cash volume for the day. The field is left out rather than sent as a partial sum.
  • Days before 2026-10-23 keep their total_volume.
  • markets_traded, cumulative_profit, daily_change, and every other field are unchanged on all days.
  • stats.total_volume on GET /api/v1/trader/{address}, the wallet’s full-history volume from Polymarket, is unchanged.
Backward compatible. The field was already optional and documented as left out when unavailable.What to change: If you sum total_volume over a range that reaches 2026-10-23, treat a missing value as unknown, not zero.
Leaderboard entries carry the wallet's sports and esports record as in_scope
Each entry on GET /api/v1/leaderboard now carries in_scope, the wallet’s record on sports and esports markets. It is the same object as pnl.in_scope on GET /api/v1/trader/{address}, as of the leaderboard’s last refresh.Before this change, a leaderboard entry carried only the wallet’s figures for every Polymarket market, so a client that wanted the sports and esports figure the grade ranks had to request each wallet’s profile.
  • in_scope holds basis, realized_pnl, markets, markets_resolved, win_rate, markets_out_of_scope, and as_of.
  • in_scope is left out until 0xinsider has computed the wallet’s record. A missing in_scope never means zero.
  • pnl, realized_pnl, pnl_correction, and win_rate keep the wallet’s figures for every market.
Backward compatible. The field is additive.What to change: Nothing. To show the figure the grade ranks, read in_scope.realized_pnl and in_scope.win_rate.
The games catalog adds UEFA Europa League and Conference League coverage
GET /api/v1/games now includes UEFA Europa League games as league=uel and UEFA Conference League games as league=uecl, both under sport=Soccer. coverage.leagues lists both keys. Use sport=Soccer&league=uel or sport=Soccer&league=uecl to list them, then GET /api/v1/games/{event_slug} for one game’s linked markets.Before this change, neither competition had its own scope. Their games came through the general Soccer scope, and a game’s league was the provider’s live-score code (col for a Conference League game) or null.GET /api/v1/edge-hunter now reports Conference League rows with market_context.league set to uecl. Before, it was europa-conference-league. A leagues=europa-conference-league selection still matches these rows, because selections normalize to the same key. Europa League rows already read uel.Backward compatible. The league coverage is additive. Request parameters and response fields are unchanged.What to change: If you compare league or market_context.league against col or europa-conference-league, compare against uecl instead.
Wallet grades rank realized P&L on sports and esports markets only
grade and score on GET /api/v1/trader/{address}, POST /api/v1/traders/batch, and every other route that returns a wallet’s current grade now rank the wallet’s realized P&L on sports and esports markets. The resolved-market floors for S, A, and B count resolved sports and esports markets, and the win rate inside the grade counts decided sports and esports markets.Before this change, the grade ranked the wallet’s realized P&L on every Polymarket market, and the floors and the win rate counted every market.
  • The graded figure is the sports and esports share of Polymarket’s realized P&L for the wallet: the P&L of those markets, plus their share of rebates and of the difference between Polymarket’s wallet total and its per-market figures. pnl.in_scope.realized_pnl on GET /api/v1/trader/{address} is the same figure.
  • pnl.realized, pnl.correction.realized, and the other P&L fields keep Polymarket’s figures for the whole wallet.
  • Grades change at the first grading pass after the release, which runs about every hour. A wallet with little sports and esports activity can move down to C or lower.
  • Historical grades from GET /api/v1/trader/{address}/grade-at keep the grade recorded on their date, so a grade from before this change ranked every market.
Backward compatible. No field, value, or type is added or removed.What to change: Nothing. If you compare a wallet’s grade across October 22, 2026, expect the basis to differ.
Export freshness_at and category_data_as_of say when the wallet's positions were last confirmed current
In the wallet dataset export from POST /api/v1/trader/{address}/export, risk_metrics.*.freshness_at, category_performance.freshness_at and export_metadata.category_data_as_of now state when the wallet’s positions were last confirmed current. That is the older of two times: the last sync that read the wallet’s whole closed-position history, and the last complete read of its open positions.Before this change, these fields gave the time the wallet’s oldest unchanged market row was last written. A settled market is never rewritten, so a wallet that synced today could read months old. On October 22, 2026, 200 wallets synced in the previous 24 hours read a median of 175 days old.
  • A wallet whose syncs stall still reads old, so the fields still tell you when data is behind.
  • Each wallet gets the new time at its next sync that reads its whole closed history. Until then, the fields keep the old time.
  • The values the fields describe do not change.
Backward compatible. No field, value, or type is added or removed.What to change: Nothing. If you skip or flag wallets by these fields, expect most wallets to read recent instead of weeks or months old.
Pick of the Day locked-only responses type supersedes_pick_id as a nullable string
GET /api/v1/pick-of-the-day now declares supersedes_pick_id as a deprecated nullable string on PickOfTheDayNoEntitledPicks, the response a paid caller gets when every published pick needs a higher plan. Every other Pick of the Day shape already declares it this way, and SDK 0.31.0 carries the new type.Before this change, the OpenAPI document declared the field as null only (type: ["null"], enum: [null]). The Go and Rust client generators cannot read that declaration, so those clients have not regenerated since October 12.
  • The API still sends null in this field on every response.
  • SDK 0.31.0 types the field string | null. Earlier releases typed it null.
  • The get_pick_of_the_day MCP output schema declares the same type after the next backend release.
  • The Go and Rust clients regenerate from the corrected document.
Breaking for TypeScript code that assigns supersedes_pick_id to a variable typed null. Response data is unchanged.What to change: Nothing for most clients. In TypeScript, type the field string | null, or stop reading it and identify a pick by pick_id.
API, SDK and MCP descriptions and examples cover sports and esports markets only
The OpenAPI document, /agents.md, /llms-full.txt, the MCP server, SDK 0.30.0 and MCP package 3.6.2 now describe and give examples for sports and esports markets only. This follows the October 21 changes that limited the API to those markets.Before this change, several descriptions and examples still named categories and markets outside sports and esports: in rejection notes, in response examples and in the search example’s q.
  • The OpenAPI info.description states the scope. A market, event or trade outside sports and esports answers 404 with error.code: "not_found" and error.reason: "market_out_of_scope", and you should not retry it. A category outside them answers 400 with error.param category.
  • Response examples for trader categories, trader context, sharp-money and smart-money flows, and monthly reports use sports markets. Search markets and the leaderboard examples use sports values, such as q=lakers and category=Basketball.
  • The MCP tool explore_markets describes category as a sport or esports bucket, and the server instructions state the scope. Both serve after the next backend release.
  • SDK 0.30.0 adds types already in the API: MarketOutOfScopeError for the 404 above, pnl.in_scope (TraderPnlInScope), report.market_scope, product_scope on trader exports, Edge Hunter’s admission: "most_held_48h" and departures (EdgeHunterObservationDeparture), and category_avg_price on MarketHolder and PickHolder.
  • The @0xinsider/mcp package 3.6.2 carries the same explore_markets text.
Backward compatible. Routes, parameters and response fields are unchanged.What to change: Nothing. To handle the scope in code, catch MarketOutOfScopeError in SDK 0.30.0 and stop requesting that market.
Webhook signatures can carry up to four candidates while 0xinsider rotates its signing key
The x-0xinsider-signature header on webhook deliveries now carries one more v1=<hex> candidate while 0xinsider rotates the server key that every webhook signing secret is derived from. The extra candidate is signed with the secret you already hold, so your receiver keeps verifying through the rotation.Before this change, the header carried one candidate, or two during a staged rotation of your own secret.
  • Outside a rotation, nothing changes: one candidate, or two during your staged rotation.
  • During our rotation: two candidates, or up to four when your staged rotation overlaps it.
  • The first candidate is always the current secret’s.
  • verifySignature in the TypeScript client already accepts any matching candidate.
Backward compatible for receivers that split the header on commas and accept any match, as the verification guide shows. Breaking for a receiver that compares the whole header to one signature or reads only the first two candidates.What to change: Split x-0xinsider-signature on commas and accept the request when any candidate matches. During a rotation, rotate your webhook secret to move to the new key; see When 0xinsider rotates its signing key.
Wallet trading styles count the wallet's sports and esports markets only
strategy_type on GET /api/v1/leaderboard, and strategy.strategy_type on GET /api/v1/trader/{address} and POST /api/v1/traders/batch with expand=strategy, now describe the wallet’s sports and esports markets only. The leaderboard’s strategy filter selects on the same styles.Before this change, the style counted every market 0xinsider stored for the wallet, in any category.
  • A wallet with fewer than 20 sports and esports markets is unclassified, however many other markets it traded.
  • Both-side shares, fills per market, and category shares are measured over sports and esports markets, so category_focused and diversified compare sports and esports categories with each other.
  • Measured on October 22, 2026, 94,609 of 285,315 classified wallets change style, 67,219 of them to unclassified.
  • Stored styles are rewritten in the background after the release, which takes several hours. Until a wallet’s style is rewritten, it still counts every market.
Backward compatible. No field, value, or type is added or removed. See Wallet trading styles for the rules.What to change: Nothing. If you store styles, expect about a third of them to change once, and read unclassified as fewer than 20 sports and esports markets or too little usable history.
Positions board and wallet reads list sports and esports positions only
GET /api/v1/positions now lists positions on sports and esports markets only, on every read: the board, its min_grade pages, and wallet reads.Before this change, a request without category or condition_id listed open positions on every market 0xinsider tracks, such as politics and crypto. On October 21, 2026, 1,904 of the 2,000 largest open positions on the board were on such markets.
  • A wallet read returns that wallet’s sports and esports positions only. A wallet that holds no sports or esports position returns an empty list.
  • A sports market filed under another category is listed when 0xinsider has classified it as sports, by the same rule as the large-trade lists.
  • Reads with category or condition_id are unchanged. They already refuse a category or market outside sports and esports.
  • Response fields, ordering, and the cursor format are unchanged. The get_positions MCP tool reads this route and follows the same rule.
Breaking for clients that read positions on other markets from the board or a wallet read.What to change: Expect no position on a market outside sports and esports. Positions on other markets are no longer available from this route.
Trader exports hold sports and esports trades and markets only
POST /api/v1/trader/{address}/export now writes a file whose trades and markets are sports and esports markets only, the markets the wallet page lists. GET /api/v1/trader/{address}/export counts the same markets.Before this change, the file held every market and trade of the wallet.
  • The rule applies to the trades in every format (json, ndjson and csv), to markets, and to category_performance.by_category.
  • A market is in scope when 0xinsider has classified it as a sports or esports market. A market that is not classified yet is left out.
  • trader.product_scope_pnl is new: the wallet’s sports and esports realized P&L, the figure the wallet page shows. It is omitted until it has been computed.
  • pnl, summary, the rest of trader, risk_metrics, quant_metrics, risk_summary, and the duration and hour buckets of category_performance still cover every market of the wallet. export_metadata.scope_note says so in the file.
  • In the status response, artifact.manifest.generation.product_scope is sports_esports_v1, and artifact.manifest.generation.source_watermarks.trades.coverage is sports_esports_rows.
  • The snapshot adds product_scope. counts.exported_markets, counts.estimated_trade_rows, counts.estimated_size_mb, reconciliation.exported_market_cost_basis, source_range.latest_trade_at and source_range.latest_market_activity_at count sports and esports markets only.
  • A job’s total_trades is null until the file’s rows are known, and then equals the file’s trade rows. Before, it was an estimate set at submit.
  • A submit no longer returns a ready file written before this change. It queues a new job.
Breaking for clients that expect every market of the wallet in the file, or a number in total_trades right after submit.What to change: Read artifact.manifest.generation.product_scope to tell a scoped file from an older one, and treat a null total_trades as unknown. A wallet with no sports or esports markets now exports a file with no trade rows.
Trader context.md names the position breakdown as covering every market category
GET /api/v1/trader/{address}/context.md now titles its position section ## Position breakdown (synced markets, all Polymarket categories).Before this change, the heading was ## Position breakdown (synced markets). The counts and P&L under it were the same, and they include markets outside sports and esports.
  • The position_summary description on GET /api/v1/trader/{address}/context now says it counts all Polymarket markets.
  • The GET /api/v1/trader/{address}/pnl description and the get_trader_pnl MCP tool now say the daily series covers all Polymarket markets. Polymarket reports this figure for the whole wallet, so it cannot be split per market.
Backward compatible. Every value and every JSON field is unchanged.What to change: If you match the old heading text in context.md, match the new one, or match on the ## Position breakdown prefix.
Edge Hunter wider_holder responses list cards that left before kickoff, and why
GET /api/v1/edge-hunter with view=observations&cohort=wider_holder now returns departures: each market whose card was in an earlier snapshot of the same selection, is not in this one, and has not kicked off. It works for the default selection and for admission=most_held_48h.Before this change, a card that left before kickoff stopped appearing, and the response did not say why.
  • Each entry has condition_id, event_slug, category, admitted_by, game_start_time, last_observed_at, departed_at and reason.
  • reason uses the funnel’s terminal vocabulary. primary_slate_candidate means the market moved to view=signals, and split_holder_pile means its graded holders split.
  • An entry stays until its kickoff or until the card returns. While it stays, a reason that only says a read did not finish, such as holder_deadline_unavailable, is replaced by the market’s later outcome; every other field, and any other reason, stays fixed.
  • The list holds at most 336 entries, newest first. It follows your category and selectors and is part of the ETag.
  • The field is omitted on in_play and emerging_pile, and on a snapshot that could not establish its departures.
  • The SDK adds the EdgeHunterObservationDeparture type, and the get_edge_hunter MCP output schema adds the field.
Backward compatible. Rows, cursors and every other field are unchanged.What to change: Nothing. To learn why a card is gone, read its departures entry, and treat a missing departures field as unknown.
Large-trade, flag and market lists include sports markets filed under another category
GET /api/v1/large-trades, GET /api/v1/large-trades/history, their /api/v1/whale-trades aliases, GET /api/v1/events/feed/since, POST /api/v1/datasets/whale-trades, GET /api/v1/suspicious-trades with its /insider-radar alias, GET /api/v1/markets/explore and GET /api/v1/markets/search now include a sports or esports market that Polymarket files under another category. They use the same scope as the market routes.Before this change, these lists judged a market by its category alone. A market in a sports event but filed under another category, such as a Super Bowl MVP prop filed as Big Game, was left out of the lists, although its market and trade pages served it.
  • On October 21, 2026, this adds 19 markets and their 102 stored large trades, the newest from July 1, 2026.
  • A market that enters or leaves the sports and esports scope reaches the lists within 10 minutes while it is open and for a week after it resolves, and within 160 minutes after that.
  • These markets fall outside every sports and esports category value, so they show only in a list without a category filter.
  • A mode=stable walk of suspicious trades now also answers 400 with error.reason: "cursor_expired" when a market with a flag enters or leaves the scope during the walk.
  • A since poll does not return the older trades again. Read the list or history to get them.
Backward compatible. Fields, envelopes and status codes are unchanged.What to change: Nothing. Restart a stable walk from page 1 on cursor_expired, as before.
Pick of the Day issues entry authorizations for picks released during a slow internal read
GET /api/v1/pick-of-the-day now issues an entry_authorization for a pick released while one of our internal reads is slow, when a recent copy of that data is available.Before this change, a slow internal read at release could publish a pick without entry_authorization, and automated clients skipped it.
  • Authorizations already issued are unchanged. A pick published without one stays without one.
  • A pick can still publish without entry_authorization when no recent copy is available.
  • policy_version stays 8, and response fields are unchanged.
Backward compatible.What to change: Nothing. Keep skipping an automated entry when entry_authorization is missing or expired.
Trader reads add the sports and esports P&L and refuse non-sports categories and markets
GET /api/v1/trader/{address} and POST /api/v1/traders/batch now carry pnl.in_scope, the wallet’s sports and esports record. This is the P&L the 0xinsider profile now shows as its headline. Every other pnl field keeps its meaning and still covers all of the wallet’s Polymarket markets.pnl.in_scope holds these fields:
  • realized_pnl: the wallet’s realized P&L on sports and esports markets, in USD, or null when Polymarket publishes no realized figure for the wallet. It splits Polymarket’s realized P&L, with any published pnl.correction, by market and shares fees, refunds and rebates out by cost. A wallet that trades only sports keeps the full figure, and a wallet with no sports market gets 0.
  • markets, markets_resolved and win_rate (0 to 1, or null): the wallet’s sports and esports markets.
  • markets_out_of_scope: how many of the wallet’s markets are outside sports and esports.
  • basis names the split rule, now sports_esports_split_v1, and as_of dates the figures.
pnl.in_scope is left out until 0xinsider has computed the wallet’s record. A missing object means the record is not ready yet, not a P&L of zero.Four routes also follow the sports and esports scope. 0xinsider now serves sports and esports markets only.The MCP tools get_trader, batch_get_traders, get_trader_context, get_trader_categories, get_position_timeline, get_position_timeline_by_id and get_positions read these routes and follow the same rules. GET /api/v1/trader/{address}/context.md adds a line for the sports and esports realized P&L.Backward compatible for pnl.in_scope, which is additive. Breaking for clients that ask for a non-sports category or market on the other four routes.What to change: Read pnl.in_scope.realized_pnl for the sports and esports figure. Filter by a sport or esports category, and stop requesting a market that answers market_out_of_scope.
Pick of the Day issues entry authorizations for high-priced picks it used to skip
GET /api/v1/pick-of-the-day now issues an entry_authorization for high-priced picks that could not get one before. For those picks, a newly issued max_entry_price can be up to 1 cent higher than before.Before this change, the price ceiling for a high-priced pick was rounded down to the market’s price increment, which could leave it below the lowest ask. Such a pick published without entry_authorization, and automated clients skipped it.
  • Authorizations already issued keep their recorded max_entry_price and expires_at. A pick published without one stays without one.
  • policy_version stays 8, and response fields are unchanged.
  • The Pick of the Day reference and the auto-buy guide now explain when entry_authorization is missing.
Backward compatible.What to change: Nothing. Keep skipping an automated entry when entry_authorization is missing or expired. This change needs no potd-trader upgrade.
potd-trader v0.4.4 checks for new picks every minute by default
potd-trader v0.4.4 watch checks for newly released picks every minute when no release time is known, and prints that interval when it starts. Scheduled release times, Retry-After, and proof_pending_picks[].retry_at still set the next check when they are sooner.Before this change, WATCH_IDLE_MINUTES defaulted to 30, so a pick released without a scheduled time could be seen up to 30 minutes late.Backward compatible. A WATCH_IDLE_MINUTES value in your .env still wins, and spending limits and order guards are unchanged.What to change: Upgrade to v0.4.4. If your .env came from an older .env.example and sets WATCH_IDLE_MINUTES=30, set it to 1 or delete the line.
Edge Hunter observations offer the most-held 48-hour wider_holder selection
GET /api/v1/edge-hunter with view=observations&cohort=wider_holder accepts a new parameter, admission=most_held_48h. It returns, per sport, up to 8 wider_holder markets that kick off within 48 hours, most graded holders first, then most volume, then soonest kickoff, with at most 4 per event. The selection is made again on every snapshot, so a market with more graded holders takes the place of one with fewer.Before this change, the observations view offered only the default selection: the 8 soonest kickoffs per sport plus up to 8 most-held markets within 24 hours, each kept until kickoff. The most-held 48-hour selection is the one the view used before October 17, 2026.
  • Every row of an admission=most_held_48h response has admitted_by: "most_held_48h", a new enum value, and the response echoes admission at the top level.
  • funnel, coverage, degraded, and degradation_reasons describe that selection.
  • Any other view or cohort returns 400 with error.param: "admission". Cursors and ETag values bind admission.
Backward compatible. A request without admission returns exactly what it did before, and no default row carries most_held_48h.What to change: Nothing. To keep a record on the pre-October 17 selection, add admission=most_held_48h to your cohort=wider_holder requests. A strict admitted_by enum check must accept most_held_48h on those responses.
Combos serve combos whose every leg is a sports or esports market
GET /api/v1/combos/fills and GET /api/v1/combos/summary now leave out a combo with any leg on a market outside sports and esports. GET /api/v1/combos/{condition_id} answers such a combo 404 with error.code: "not_found" and error.reason: "market_out_of_scope". The MCP tools get_combo_fills, get_combos_summary and get_combo read these routes and follow the same rule. 0xinsider now serves sports and esports markets only.Before this change, a combo with a Politics, Geopolitics or Crypto leg was listed, counted and served. On October 21, 2026, 596 combos had such a leg: 663 of 1,578,764 taker fills, and 424 of the 4,738 combos in the live count.
  • Page sizes, cursors, offsets and has_more describe the in-scope fills only. Cursors issued before the change stay valid.
  • The summary’s live count drops by the out-of-scope combos within one five-minute refresh.
  • A combo whose every leg is a sports or esports market is unchanged: same fields, envelopes and status codes.
Breaking for clients that read combos with a leg outside sports and esports.What to change: Expect no combo with a leg on another market, and stop requesting a combo that answers market_out_of_scope.
Reports for periods ending on or after October 21, 2026 count sports and esports markets only
GET /api/v1/reports, GET /api/v1/reports/daily, GET /api/v1/reports/weekly, GET /api/v1/reports/monthly and the MCP report tools now build a report whose period ends on or after October 21, 2026 over sports and esports markets only: totals, categories, top_large_trades and grade_distribution leave out every other market. 0xinsider now serves sports and esports markets only.A report whose period ended earlier is a published record and does not change: same numbers, same snapshot.version.Every report body carries a new field, report.market_scope: sports_and_esports for a period ending on or after October 21, 2026, all_markets for an earlier one. On October 20, 2026, 54 of 408 large trades (13.2%) and 10.3% of large-trade volume were on markets outside sports and esports; for September 2026, 1,519 of 13,313 (11.4%).Backward compatible. The new field is additive, and no request changes. A weekly or monthly period that contains October 21, 2026 counts sports and esports only for the whole period, so its totals are lower than a sum of the earlier daily reports inside it.What to change: Read report.market_scope before comparing totals across October 21, 2026.
Sharp-money flows and the leaderboard serve sports and esports only
GET /api/v1/markets/sharp-money-flows and its deprecated smart-money-flows alias now rank sports and esports markets only. On both, and on GET /api/v1/leaderboard, a category outside sports and esports answers 400 with error.code: "bad_request" and error.param: "category". GET /api/v1/coverage and its /platforms alias now say that coverage is sports and esports only; their response body is unchanged.Before this change, flows ranked markets in every category, and these routes accepted any category. On October 21, 2026, 84 of the 646 markets in the 7-day S/A/B flows ranking were outside sports and esports: $5.0M of $55.6M in ranked volume.
  • Use a sport or esports bucket for category: Basketball, Football, Baseball, Hockey, MMA, Boxing, Soccer, Cricket, Golf, Tennis, Esports, Racing, Table Tennis, Pickleball, and the umbrella Sports. A league value such as NBA still resolves to its bucket; an empty category still means every sport.
  • A flows cursor taken before this change can answer cursor_expired, because the ranked set changed. Request the first page again.
  • Every sports and esports result is unchanged: same fields, envelopes, cursors and status codes.
Breaking for clients that read flows or the leaderboard for a non-sports category.What to change: Send only sport or esports category values. Expect flows to list sports and esports markets only.
Large-trade lists, replay and datasets return trades on sports and esports markets only
GET /api/v1/large-trades (including since polls and sort=market_volume_share), GET /api/v1/large-trades/history, their /api/v1/whale-trades aliases, GET /api/v1/events/feed/since and POST /api/v1/datasets/whale-trades now leave out large trades on markets outside sports and esports. 0xinsider now serves sports and esports markets only.Before this change, these reads returned stored large trades in every category. On October 21, 2026, 10.5% of the previous 24 hours’ large trades and 26.2% of the 943,303 stored ones were on markets outside sports and esports.
  • On the list and history, a category outside sports and esports answers 400 with error.code: "bad_request" and error.param: "category", where it answered 200. Use a sport or esports bucket: Basketball, Football, Baseball, Hockey, MMA, Boxing, Soccer, Cricket, Golf, Tennis, Esports, Racing, Table Tennis, Pickleball, or the umbrella Sports.
  • A dataset request whose condition_id names an out-of-scope market answers 404 with error.code: "not_found" and error.reason: "market_out_of_scope", and reserves no job. A dataset without condition_id holds in-scope trades only, so its row count can be lower than before for the same window.
  • Pages, has_more, cursors and replay positions describe the in-scope trades only. Cursors issued before the change stay valid.
  • Every sports and esports trade is unchanged: same fields, envelopes and status codes.
Breaking for clients that read large trades on non-sports markets.What to change: Send only sport or esports category values, and do not expect large trades on other markets from any list, replay or dataset.
Large positions and suspicious trades list sports and esports markets only
GET /api/v1/large-positions and GET /api/v1/suspicious-trades, with its deprecated /insider-radar alias, now list positions and flags on sports and esports markets only. GET /api/v1/suspicious-trades/{id} and its /insider-radar/{id} alias answer 404 with error.code: "not_found" and error.reason: "market_out_of_scope" for a flag on a market outside them. 0xinsider now serves sports and esports markets only.From the same release, a trade on a market outside sports and esports is no longer scored, so it gets no new flag and no suspicious_trade_flagged webhook event.Before this change, both lists covered every Polymarket market. On October 21, 2026, 43 of the 51 rows on the first page of large positions, and 554 of the 1,114 stored flags, were on markets outside sports and esports.
  • On large positions, a condition_id that names a market outside sports and esports answers 404 not_found with error.reason: "market_out_of_scope", and a category value outside them answers 400 with error.code: "bad_request" and error.param: "category". An unknown but well-formed condition_id still returns an empty list.
  • Lists keep their cursors, ordering and page sizes; a page is never short because a row was left out.
  • Every position and flag on a sports or esports market is unchanged: same fields, envelopes and status codes.
  • The reason is terminal. It carries no Retry-After, and the answer does not change on a retry.
Breaking for clients that read large positions or flags on non-sports markets.What to change: Send only sport or esports category values, and treat error.reason: "market_out_of_scope" as final for that market or flag. The @0xinsider/sdk client raises it as MarketOutOfScopeError, a NotFoundError.
Market search, explore and batch flow serve sports and esports markets only
GET /api/v1/markets/search and GET /api/v1/markets/explore now return sports and esports markets only, and answer 400 with error.code: "bad_request" and error.param: "category" for a category outside them. POST /api/v1/markets/flow/batch and its /markets/intel/batch alias answer each out-of-scope item with its own market_out_of_scope error. 0xinsider now serves sports and esports markets only.Before this change, search and explore returned markets in every category, and a batch served flow for any market. On October 21, 2026, 30,055 of the 88,490 markets that explore and search could return were outside sports and esports.
  • Use a sport or esports bucket for category: Basketball, Football, Baseball, Hockey, MMA, Boxing, Soccer, Cricket, Golf, Tennis, Esports, Racing, Table Tennis, Pickleball, and the umbrella Sports. Matching is case-insensitive; an empty category still means every sport.
  • In a batch, an out-of-scope item has status: "error", error.code: "not_found" and error.reason: "market_out_of_scope". The other items and the 200 response are unchanged, and the item still counts one batch unit, like any other refused item.
  • Every sports and esports result is unchanged: same fields, envelopes, cursors and status codes.
Breaking for clients that search, explore or batch-read non-sports markets.What to change: Send only sport or esports category values, and treat a batch item’s error.reason: "market_out_of_scope" as final for that market.
Large trades on markets outside sports and esports answer 404 market_out_of_scope, and no new ones are recorded
GET /api/v1/large-trades/{id}, its counterparty executions and makers pages, and their /api/v1/whale-trades aliases now answer 404 with error.code: "not_found" and error.reason: "market_out_of_scope" for a large trade whose market is outside sports and esports. 0xinsider now serves sports and esports markets only.From the same release, a large fill on a market outside sports and esports is no longer recorded as a large trade. It gets no wt_ id, no event on the stream or the event replay feed, and no large-trade webhook event.Before this change, these routes answered 200 for a large trade on any Polymarket market. In the 7 days to October 21, 2026, 356 of 3,373 new large trades were on markets outside sports and esports.
  • A well-formed id with no stored large trade still answers a plain 404 not_found with no reason.
  • Every large trade on a sports or esports market is unchanged: same fields, envelopes and status codes.
  • The reason is terminal. It carries no Retry-After, and the answer does not change on a retry.
  • The large-trade list, history and dataset routes still return stored out-of-scope trades until a later release removes them. That release will get its own entry here.
Breaking for clients that read large trades on non-sports markets by id.What to change: Treat error.reason: "market_out_of_scope" as final and stop requesting that trade. The @0xinsider/sdk client raises it as MarketOutOfScopeError, a NotFoundError.
Market routes answer 404 market_out_of_scope for a market outside sports and esports
The six single-market routes now answer 404 with error.code: "not_found" and the new error.reason: "market_out_of_scope" for a market outside sports and esports: holders, flow, intel, snapshot, candles and context.md. 0xinsider now serves sports and esports markets only.Before this change, these routes answered 200 with data for any Polymarket market, including crypto, politics and other non-sports markets.
  • A market is in scope when Polymarket marks it as a sports market, or when any market in its Polymarket event is one.
  • A condition id with no stored market still answers a plain 404 not_found with no reason.
  • Every in-scope answer is unchanged: same fields, envelopes and status codes.
  • The reason is terminal. It carries no Retry-After; the answer does not change on a retry or under another URL for the same market.
Breaking for clients that read non-sports markets through these routes. On October 21, 2026, none of 612 sampled market reads asked for one.What to change: Treat error.reason: "market_out_of_scope" as final and stop requesting that market. The @0xinsider/sdk client raises it as MarketOutOfScopeError, a NotFoundError, from its next release.
Pick of the Day voids a pick whose game is suspended or postponed past 72 hours
A published pick now settles void when Polymarket reports its game suspended or postponed and the game has not completed 72 hours after the pick’s committed kickoff. The void is final: if the game resumes and its market resolves later, the pick stays void. The archive and the ledger report it as outcome: "void".Before this change, such a pick stayed pending until Polymarket resolved its market. The rules of those markets keep them open until the game is completed, which can be weeks or never. Pick 578, Rayo Vallecano de Madrid vs. Athletic Club on October 10, 2026, was suspended at 0-0 and still read pending ten days later.
  • The suspension or postponement comes from Polymarket’s own game status, never from a price.
  • A void of this kind is treated like any other void: it counts in void, and it is neither a win nor a loss. stake_usd, return_usd, return_per_100, payout_display, and unit_score are omitted, as for every void.
  • resolved_at is the time the pick turned void. It does not move when the market resolves later, because the pick is not re-mapped.
  • A void from a market that settled 50-50 still follows a later correction of that market.
Backward compatible. No field is added, removed, or retyped. void was already a value of outcome.What to change: Nothing, unless you settle picks from the market yourself. Then treat a pick the API reports void as final, even if its market later resolves to a winner.