> ## Documentation Index
> Fetch the complete documentation index at: https://docs.0xinsider.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> The Markdown of an API reference page leaves out the OpenAPI schema.
> Every object an endpoint returns or a webhook carries, with each field's type, presence and meaning, is on https://docs.0xinsider.com/api-reference/objects.md.
> The full OpenAPI 3.1 spec names each operation's and each webhook's exact parameters, request body and response schema: https://docs.0xinsider.com/api-reference/openapi.json.

# API changelog: October 17 to 20, 2026

> 29 API, SDK, CLI, MCP, OAuth, and feed changes from October 17 to 20, 2026, newest first, each with its effect on clients. Newer ones are on the API changelog.

These are the API changelog entries from October 17 to 20, 2026, newest first. The newest changes are on the [API changelog](https://docs.0xinsider.com/changelog.md).

**October 20, 2026**

Schema Feed Article lines no longer carry a speakable selector

[`GET /feeds/research.jsonl`](https://0xinsider.com/feeds/research.jsonl), [`/feeds/learn.jsonl`](https://0xinsider.com/feeds/learn.jsonl), and [`/feeds/news.jsonl`](https://0xinsider.com/feeds/news.jsonl) now serve each `Article` without a `speakable` property. The research and learn results of [`GET /ask`](https://0xinsider.com/ask) and each page's JSON-LD drop it too.

Before this change, every `Article` carried `speakable.cssSelector` `["h1", "[data-speakable]"]`. No research, learn, or news page renders a `data-speakable` element, so validator.schema.org reported `NO_MATCHES_FOUND` on each of those pages.

**Backward compatible.** schema.org makes `speakable` optional, and `headline` carries the same text as the page's `h1`.

**What to change:** Nothing. A consumer that read `speakable` reads `headline` instead.

**October 20, 2026**

Explore's change\_pct\_24h measures a full 24 hours, or is null

[`GET /api/v1/markets/explore`](https://docs.0xinsider.com/api-reference/endpoint/explore-markets) now computes `change_pct_24h` and `no_change_pct_24h` from the price exactly 24 hours ago, to within 2 minutes. `price_points` and `no_price_points` start at that price, so the first point and the change describe the same window.

Before this change, the series started at the first whole hour after that moment, so each change covered 23 to 24 hours. Measured on October 20, 2026 across every market with a published change, the starting price was off by more than 2 cents in about 1 in 150 reads, and by up to 39.5 cents on a fast-moving market.

* A market younger than 24 hours now has `change_pct_24h: null` instead of a change over its shorter life. Its `price_points` still return.
* A resolved market whose price series stopped when trading closed also has `change_pct_24h: null`. Its old figure measured the last in-play price, not the resolution, and on October 20, 2026 it was up to 80 cents away from Polymarket's own 24-hour change.
* `score_components.price_move_signal` is `null` whenever both changes are, so `discover_score` gives such a market no credit for a price move.
* The `explore_markets` MCP tool returns the same values.

**Backward compatible.** No field is added, removed, or retyped. Both fields were already nullable.

**What to change:** Nothing. If you computed a change from `price_points[0]`, it now matches `change_pct_24h`.

**October 19, 2026**

Remote MCP refuses a bad Origin or protocol header before it reads the body

[`POST /api/v1/mcp`](https://docs.0xinsider.com/api-reference/endpoint/remote-mcp) with an API key or OAuth token again checks the `Origin` and `MCP-Protocol-Version` headers before it reads the request body. A disallowed `Origin` answers `403`, and an unsupported `MCP-Protocol-Version` answers `400` with JSON-RPC error `-32600`, whatever the size of the body. Neither refusal counts against your request limits.

Before this change, from October 18, a keyed POST read up to 1 MiB of its body before these checks:

* A body over 1 MiB got the `Failed to read request body` error instead of the `403` or `400`.
* A slow body delayed the refusal until it arrived.
* A refused `tools/call` counted against the per-minute allowance, the monthly quota, and pay-as-you-go usage.

**Backward compatible.** The refusals are the ones this endpoint documents; only the order of the checks changes back.

**What to change:** Nothing.

**October 19, 2026**

Edge Hunter observations keep a same-event market when the 168-market limit is full

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations` now keeps a place for a most-held `wider_holder` market inside its event's limit of 4 only when the limit of 168 markets in all has room for it. When the soonest kickoffs and in-play markets fill the 168, the most-held market gives up that place, and another market of the same event can take it.

Before this change, the most-held market kept the place even when the 168 were full. A market of the same event among the soonest kickoffs was then left out and counted in `coverage.capacity_limited_markets`, and the most-held market was left out as well.

**Backward compatible.** No field, parameter, or enum value changes. The limits stay 8 markets per group and sport, 4 per event, and 168 in all.

**What to change:** Nothing.

**October 19, 2026**

Holder win rates carry the wallet's average price paid, category\_avg\_price

[`GET /api/v1/market/{condition_id}/holders`](https://docs.0xinsider.com/api-reference/endpoint/get-market-holders) and the `display_holders` entries of [`GET /api/v1/pick-of-the-day`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day) now return `category_avg_price` beside a measured `category_win_rate`. It is the wallet's average entry price in the same category, from 0 to 1, so 0.98 is 98 cents.

Before this change, a holder carried only the win rate and its record. A wallet that buys outcomes that are already near-certain wins almost every time, so a 99% win rate with no price could read as skill. One MLB holder won 1,532 of 1,543 markets, and 1,361 of them were bought at 98 cents or more.

* The sample is the wallet's settled markets in the category of \$20 or more where it bought one side at a known price. It is the sample behind the Edge column on the sport leaderboards, and it can differ from the `category_win_record` sample, which counts every trade size.
* The field is present only when `category_win_rate_status` is `measured` and that sample has at least 5 markets. It is absent otherwise, never `null`.
* On an esports market or pick, the price is the `Esports` category's, also when `category_win_rate_game` is present. There is no per-game price.
* The MCP tools `get_market_holders` and `get_pick_of_the_day` return the same field.

**Backward compatible.** One optional field is added.

**What to change:** Nothing. To show the context the 0xinsider chips show, print the price beside the win rate when it is 0.90 or more.

**October 18, 2026**

Games no longer report a period past the map that decided an esports series

[`GET /api/v1/games`](https://docs.0xinsider.com/api-reference/endpoint/list-games) and [`GET /api/v1/games/{event_slug}`](https://docs.0xinsider.com/api-reference/endpoint/get-game) now keep an esports series' `status.period` on the map that decided it. When one side has won the majority of a best-of series, `period` reads that map, for example `2/3` for a best-of-3 won 2-0.

Before this change, `period` could read the next map for about 20 seconds, for example `3/3` beside a 2-0 score in a best-of-3, before the game ended and it returned to `2/3`. No such map is ever played.

**Backward compatible.** No field, parameter, or enum value changes. The scores and every other `status` field are unchanged.

**What to change:** Nothing.

**October 18, 2026**

Combo fills: a result filter lists a combo only when recorded and current results agree

With `result` set, [`GET /api/v1/combos/fills`](https://docs.0xinsider.com/api-reference/endpoint/list-combo-fills) now lists a combo only when its recorded result and its current result are the same. Before, it checked only the current result. A combo whose two results differ still appears when you send no `result` filter, under its current `status`.

On October 18, 2026, no listed fill had results that differed (0 of 1,541,021). The same change makes filtered pages faster: deep pages under `result` were taking up to 14 seconds and could return `503`.

**Backward compatible.** Response fields and their meaning are unchanged.

**What to change:** Nothing.

**October 18, 2026**

Edge Hunter observations name their selection, and most-held wider\_holder markets show a day ahead and stay to kickoff

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations` adds `admitted_by` to every row. `most_held` marks the group of up to 8 markets per sport with the most graded holders, and every `in_play` row. `soonest_kickoff` marks the 8 soonest `wider_holder` kickoffs per sport. An `emerging_pile` row carries the value of its `wider_holder` row.

The most-held `wider_holder` group added earlier on October 18 now looks 24 hours ahead instead of 12, and a market in it keeps its place until its game starts. Before this change, a market with more graded holders could take the place of one already shown, which then returned only among the 8 soonest kickoffs.

* A market gives its place up when its holder read shows no observation: its graded holders split, no current graded holder is found, or its price is unavailable. A holder read that does not finish in time does not cost it its place.
* The limits stay the same: 8 markets per group and sport, 4 per event, and 168 in all. Markets beyond them still count in `coverage.capacity_limited_markets`.

**Backward compatible.** `admitted_by` is a new required field on observation rows; no field, parameter, or enum value is removed or renamed.

**What to change:** Nothing. To compare with the most-held selection the feed made before October 17, keep the rows with `admitted_by` `most_held`. Expect those rows from up to a day before kickoff, each staying until its kickoff.

**October 18, 2026**

Max allows 200 requests per minute

A Max account now allows 200 authenticated requests per minute, up from 100. Its batch item budget follows: 5,000 item units per minute, up from 2,500. Pro stays at 100 requests and 2,500 item units. See [Rate limits](https://docs.0xinsider.com/rate-limits.md).

* `RateLimit-Limit` and `X-RateLimit-Limit` report your plan's minute allowance: `200` on Max, `100` on Pro.
* On batch routes, `X-Batch-RateLimit-Limit` and `meta.rate_limit.limit` report `5000` on Max and `2500` on Pro.
* [`GET /api/v1/usage`](https://docs.0xinsider.com/api-reference/endpoint/get-usage) reports the same minute allowance in `data.rate_limit.limit`.
* The monthly quota does not change: 2,000,000 requests on Max and 500,000 on Pro. The usage and identity reads keep their shared allowance of 100 reads per minute, and the per-IP allowance stays 1,200 requests per minute.

**Backward compatible.** No request or response field changes. Only the numbers in these headers and fields change for Max.

**What to change:** Nothing. A client that paces from `RateLimit-Limit` and `RateLimit-Remaining` speeds up on its own. A client that hard-codes 100 a minute can raise it to 200 on Max.

**October 18, 2026**

Remote MCP counts only tools/call against your request limits

[`POST /api/v1/mcp`](https://docs.0xinsider.com/api-reference/endpoint/remote-mcp) now counts only `tools/call` against the per-minute request allowance, the monthly quota, and pay-as-you-go usage. Every other message is free, with or without a key.

Before this change, every message that carried a key counted as one request. A client that opens a session for each tool call spent 5 requests on it, so the 100-request minute allowance held about 20 tool calls.

* Free now: `initialize`, `ping`, `tools/list`, `notifications/initialized`, `notifications/cancelled`, and the `405` answers to `GET`, `HEAD`, and `DELETE`.
* A free message still checks the key. A wrong key answers `401`, a lapsed plan `402`, and a locked account `423`, as before.
* On a free message, `RateLimit-*` describes the per-IP allowance of 1,200 requests per minute, the same as a message without a key. It carries no `X-Monthly-Quota-*` or `X-Usage-Accounting` header.
* Free messages no longer appear in your usage counts or on a pay-as-you-go invoice.

**Backward compatible.** No request or response body changes.

**What to change:** Nothing. To pace tool calls, read `RateLimit-*` from a `tools/call` response, not from the handshake.

**October 18, 2026**

Edge Hunter wider\_holder observations show the most-held markets hours before kickoff

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations&cohort=wider_holder` now evaluates up to 8 more markets per sport: those with the most graded holders among the rest that kick off within 12 hours. The 8 soonest kickoffs per sport are evaluated as before, so a market about to start stays evaluated until kickoff.

Before this change, each sport evaluated only its 8 soonest kickoffs. In soccer they reached about 13 minutes ahead, so a soccer row first appeared a median of 14 minutes before kickoff.

* The limits of 4 markets per event and 168 in all do not change. Markets beyond them still count in `coverage.capacity_limited_markets`.
* A market in the new group can drop out before its kickoff when a market with more graded holders takes its place. It returns once it is among the sport's 8 soonest kickoffs.
* A `wider_holder` or `emerging_pile` market that kicks off more than an hour later is read again only when its last read is 10 minutes old. Until then its row carries that read, with the read's own `holder_snapshot_at` and `provider_read_source: "cached"`. The 15-minute limit on an older read does not change.
* `in_play` does not change.

**Backward compatible.** No field, parameter, or enum value changes.

**What to change:** Nothing. Expect more `wider_holder` rows, many of them hours before kickoff. Use `holder_snapshot_at` for the age of a row's holder read.

**October 18, 2026**

Pick of the Day moves the free selection when the free pick's game is cancelled

[`GET /api/v1/pick-of-the-day`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day) now keeps a free selection when the day's free pick is withdrawn because its game was cancelled, or is never published because its game ended or was cancelled before its release time. Another pick of that day becomes the free selection, and its `is_free_selection` changes from `false` to `true`.

Before this change, the day then had no free selection. This replaces the line of the earlier October 18 entry that said a withdrawn free selection keeps the designation alone.

* The new free selection is the first pick in `publication_order` that is still scheduled or published, is not withdrawn, and whose game has not started. It can be a pick you already read with `is_free_selection: false`.
* If no pick qualifies, the next addition to that day becomes the free selection, provided its game has not started.
* The withdrawn pick keeps `is_free_selection: true`. The current day and [`GET /api/v1/pick-of-the-day/archive`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-archive) leave withdrawn picks out, so they still show at most one free selection a day. [`GET /api/v1/pick-of-the-day/ledger`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger) keeps every published pick, so a ledger day can show two picks with `is_free_selection: true`: the withdrawn pick and the one that replaced it.
* Pro still opens the free selection plus the first 4 nonfree picks, so on such a day Pro opens up to 5 live picks where before it opened up to 4.
* `is_free_selection` never changes from `true` to `false` while the API serves the pick. A scheduled pick that is set aside and later restored to the schedule can return with `false`, when another pick holds the free selection by then. The Pick of the Day MCP tools return the same `is_free_selection`. Ledger proofs do not change, because a sealed pick does not include `is_free_selection`.

**Backward compatible.** No field, parameter, or enum value changes.

**What to change:** Nothing for the current day and the archive. If you take the day's free selection from the ledger, expect up to two picks with `is_free_selection: true` and use the one that was not withdrawn.

**October 18, 2026**

Pick of the Day moves the free selection when the designated pick is not released

[`GET /api/v1/pick-of-the-day`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day) now keeps a free selection when the day's designated free pick is held back at its release time. Another pick of that day becomes the free selection, and its `is_free_selection` changes from `false` to `true`.

Before this change, the day then had no free selection. On October 18, 2026, signed-in free accounts could open none of the day's 16 published picks until we corrected it at 09:15 UTC.

* The new free selection is the first pick in `publication_order` that is still scheduled or published, is not withdrawn, and whose game has not started. It can be a pick you already read with `is_free_selection: false`.
* `is_free_selection` never changes from `true` to `false` on a pick the API serves.
* Pro opens the free selection plus the first 4 nonfree picks, so on such a day Pro opens up to 5 picks where before it opened up to 4.
* If every remaining game has already started, the day has no free selection.
* A free selection that is withdrawn, rather than held back, keeps the designation.
* [`GET /api/v1/pick-of-the-day/archive`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-archive), [`GET /api/v1/pick-of-the-day/ledger`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger), and the Pick of the Day MCP tools return the same `is_free_selection`. Ledger proofs do not change, because a sealed pick does not include `is_free_selection`.

**Backward compatible.** No field, parameter, or enum value changes.

**What to change:** Nothing. If you cache picks by `pick_id`, read `is_free_selection` again instead of keeping the first value you saw.

**October 18, 2026**

Edge Hunter in-play observations never serve a cached holder read from before kickoff

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations` no longer serves an `in_play` row from a cached holder read taken before that market's own kickoff, once that kickoff has passed. Such a market now gets a new holder read, or its last in-play read from up to 10 minutes earlier.

Before this change, a holder read cached in the last minutes before kickoff could be served for up to 3 minutes after the game went live. That row's position values were priced against the pre-game market, and its `holder_snapshot_at` was earlier than its `game_start_time`.

* The check uses the market's scheduled kickoff, `game_start_time`. If a game starts late, a read cached between the scheduled and the real start can still be served.
* A market can be `in_play` because its parent event is live while its own `game_start_time` is still ahead. Its cached read is still served, because every read it can have is from before its own kickoff.
* A row with `provider_read_source: "live"` is a new read and is not affected.

**Backward compatible.** No field, parameter, or enum value changes. An `in_play` row with `provider_read_source: "cached"` whose `game_start_time` has passed now always has a `holder_snapshot_at` at or after that `game_start_time`.

**What to change:** Nothing.

**October 18, 2026**

Edge Hunter in-play observations can reuse a holder read up to 10 minutes old

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations` now keeps an `in_play` market when a refresh cannot finish its new holder read. The row serves that market's last in-play holder read for up to 10 minutes, with that read's original `holder_snapshot_at` and `provider_read_source: "cached"`.

Before this change, an `in_play` market whose holder read did not finish ended as `holder_deadline_unavailable` and was missing from that snapshot. On October 18, 2026, from 05:25 to 05:55 UTC, 172 of the 175 markets that ended that way were `in_play`.

* The reused read is always one taken after the game went live and after that market's own kickoff. A read from before kickoff is never reused for an `in_play` row.
* The 10 minutes are counted when the snapshot is computed. After 10 minutes without a new read, the market ends as `holder_deadline_unavailable` again.
* A provider error still ends the market as unavailable. Only a read that ran out of time falls back.
* `in_play` rows still need a `holder_snapshot_at` no older than 30 minutes.
* `wider_holder` and `emerging_pile` rows keep their 15-minute limit.

**Backward compatible.** No field, parameter, or enum value changes. An `in_play` row's `holder_snapshot_at` can now be up to 10 minutes old, where before it was at most about 3 minutes old.

**What to change:** Nothing. If you need a fresher in-play holder read, compare `holder_snapshot_at` with your own limit.

**October 18, 2026**

GET /api/v1/usage sends monthly\_quota.unavailable\_reason, and SDK 0.29.0 types it

[`GET /api/v1/usage`](https://docs.0xinsider.com/api-reference/endpoint/get-usage) now sends `monthly_quota.unavailable_reason` on every response that carries `monthly_quota`. It is `"usage_price_reconciliation_required"` when billing must reconcile the account's usage price before pay as you go can be used, and `null` otherwise. In that state `pay_as_you_go` is `false`.

Before this change, the route never sent the field. The entry of October 1, 2026 announced it, and the entry of October 14, 2026 removed it from the document because the route did not send it. The OpenAPI document lists it as always sent, and the TypeScript SDK 0.29.0 types it as `"usage_price_reconciliation_required" | null`.

**Backward compatible.** The field is added; no field is removed or retyped.

**What to change:** Nothing. To tell a billing problem from pay as you go being off, read `unavailable_reason` beside `pay_as_you_go`.

**October 18, 2026**

Edge Hunter observations no longer mark a snapshot degraded for the 100-holder page

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations` no longer adds `holder_scan_incomplete` to `degradation_reasons`. A market with more than 100 holders on an outcome token still shows `holder_scan_complete: false` and still counts in `coverage.incomplete_holder_markets`, but it no longer sets `degraded` to `true`.

Before this change, nearly every snapshot listed `holder_scan_incomplete`, because each market's holders come from 1 page of up to 100 per outcome token and busy markets have more. On October 17, 2026, all 1,028 snapshots from 09:00 to 22:00 UTC were `degraded`, so the flag could not separate a failed refresh from a healthy one.

* `degraded` is now `true` only for an operational cause, such as `holder_deadline_unavailable`, `provider_unavailable` or `live_source_stale`. Snapshots can still be degraded while holder reads miss their refresh deadline.
* `holder_scan_incomplete` stays in the `reason` enum, retired, and stays a funnel terminal.
* The `get_edge_hunter` MCP tool and the SDK's `edgeHunter.observations()` return the same fields and change the same way.

**Backward compatible.** No field, parameter or enum value is removed. `degraded` is `false` more often.

**What to change:** Nothing. To check holder coverage, read each row's `holder_scan_complete` or `coverage.incomplete_holder_markets`, not `degraded`.

**October 18, 2026**

Pick of the Day leaves a void pick out of every money figure

[`GET /api/v1/pick-of-the-day/archive`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-archive) now leaves a pick that settled `void` out of every money figure. A void is a pick whose market settled with no winner, such as a cricket match with no result. It stays in `picks` and in the `void` counts, and it counts as neither a win nor a loss.

Before this change, the archive valued a void at Polymarket's 50-50 payout, `stake_usd * 0.5 / backed_price` (the October 17, 2026 entry below). A favorite bought at 0.655 then read as a loss of about $237 on a $1,000 stake, for a game that had no winner.

* `picks[].stake_usd`, `return_usd`, `return_per_100`, `payout_display`, and `unit_score` are omitted for a void, as they already were for a pending pick. `picks[].backed_price` stays on a void.
* `hit_rate.net_profit_usd`, `hit_rate.staked_usd`, `hit_rate.roi_pct`, `hit_rate.unit_score`, and `days[].unit_score` leave voids out.
* `hit_rate.series[]` adds no point for a void. `hit_rate.pct` and `decided` do not change, because a void never counted in them.
* The `return_usd` on [`GET /api/v1/pick-of-the-day`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day) is omitted for a void pick in the same way.

To match the site's money from the [ledger](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger.md) at a flat stake, a win returns `stake / backed_price`, a loss returns 0, and a void or a withdrawn pick is left out.

**Backward compatible.** No field is added, removed, or retyped. Each omitted field was already optional.

**What to change:** Nothing, unless you value a void yourself. Then leave it out of profit, total stake, ROI, and units.

**October 18, 2026**

The public picks ledger leaves withdrawn picks out of its record, as the site does

The `index.json` record in [github.com/0xinsider/picks](https://github.com/0xinsider/picks) now leaves out every pick the site withdrew. Those picks are left out of `wins`, `losses`, `voids`, `decided`, and `hit_rate`, as well as the money figures. A new `record.withdrawn` and `record.proven_record.withdrawn` count them instead. The record now matches the site's and the rule this changelog gave on October 17: skip every entry whose `withdrawal_reason` is not `null`.

Before this change, the record counted a withdrawn pick in its wins, losses, and voids and left it out of the money only. On October 18, 2026 it read 348 wins, 213 losses, and 561 decided against the site's 346, 212, and 558.

* The partition is now `decided + voids + withdrawn = opened`.
* The withdrawn picks stay in `ledger/` with their commitments and real outcomes, and `verify.py` still verifies them. It prints their outcomes on a separate `withdrawn` line.
* The ledger API, [`GET /api/v1/pick-of-the-day/ledger`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger), is unchanged.

**Backward compatible.** Two keys are added, and no key is removed or retyped. `wins`, `losses`, `voids`, `decided`, and `hit_rate` drop by the withdrawn picks.

**What to change:** If you check `decided + voids == opened` on `index.json`, add `withdrawn` to the left side.

**October 18, 2026**

A trader's sync\_status no longer reads synced while a sync runs

[`GET /api/v1/trader/{address}`](https://docs.0xinsider.com/api-reference/endpoint/get-trader), [`POST /api/v1/traders/batch`](https://docs.0xinsider.com/api-reference/endpoint/batch-get-traders), [`GET /api/v1/trader/{address}/context`](https://docs.0xinsider.com/api-reference/endpoint/get-trader-context) and the MCP `get_trader` tool now return the `sync_status` and `synced_at` the trader has at the time of the request.

Before this change, a cached trader body could return `sync_status: "synced"` for up to 60 seconds after a sync had started, and the previous `synced_at` for up to 60 seconds after it had finished.

* A cached body is still served while the trader's `sync_status` and `synced_at` are unchanged, with `meta.cached` and `meta.cache_age_s` as before.
* When either has changed, the body is rebuilt from current data and `meta.cached` is `false`.

**Backward compatible.** No field, parameter, or limit changes.

**What to change:** Nothing. If you waited out the cache before trusting `sync_status`, you can read it directly.

**October 17, 2026**

Large trades before April 2, 2026 can carry a verified outcome and token\_id

[`GET /api/v1/large-trades`](https://docs.0xinsider.com/api-reference/endpoint/get-large-trades), [`GET /api/v1/large-trades/history`](https://docs.0xinsider.com/api-reference/endpoint/get-large-trades-history), [`GET /api/v1/large-trades/{id}`](https://docs.0xinsider.com/api-reference/endpoint/get-large-trade), their `whale-trades` aliases, and the whale dataset export can now return `outcome`, `token_id` and `outcome_index` for a trade recorded before April 2, 2026.

Before this change, all three were `null` for every trade before that date. Before April 2, 2026, 0xinsider stored the wrong outcome for a large share of trades on markets whose outcomes are names, such as two teams. Those trades have since been corrected. A trade before that date now serves its outcome only when the outcome was checked against the fill's own trade records and every record agreed. Any other trade from that period still serves `null`.

* The verified outcomes are being recorded in one batch. Until that batch runs, every trade before April 2, 2026 still serves `null`.
* About 93% of the 394,000 large trades before April 2, 2026 qualify. The rest stay `null`: their fill's records show both outcomes, no record exists, or the records disagree with the stored outcome.
* Trades from April 2, 2026 on are unchanged.

**Backward compatible.** No field is added, removed or retyped. The fields were already nullable.

**What to change:** Nothing. If you excluded trades before April 2, 2026 because they had no outcome, you can include the ones that now carry one. A `null` outcome still means the side is unknown, not a default.

**October 17, 2026**

Edge Hunter pre-game observations can reuse a holder read up to 15 minutes old

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations` now keeps a pre-game market in `wider_holder` and `emerging_pile` when a refresh cannot finish its new holder read. The row serves that market's last holder read for up to 15 minutes, with that read's original `holder_snapshot_at` and `provider_read_source: "cached"`.

Before this change, a holder read that did not finish ended the market as `holder_deadline_unavailable` until a later refresh read it again. On October 17, 2026, 35 markets a refresh ended that way on average, and `wider_holder` ranged from 5 to 44 rows between refreshes.

* `in_play` rows never reuse an older read.
* A provider error still ends the market as unavailable. Only a read that ran out of time falls back.
* After 15 minutes without a new read, the market ends as `holder_deadline_unavailable` again.
* Each market's holders come from 1 page of up to 100 holders per outcome token. A token with more holders leaves `holder_scan_complete` as `false`. The extra page reads that tried to complete such scans are removed; none of them ran in the previous 7 days.

**Backward compatible.** No field, parameter, or limit changes. Pre-game `holder_snapshot_at` values can be up to 15 minutes old.

**What to change:** Nothing. If you need a fresher holder read, compare `holder_snapshot_at` with your own limit.

**October 17, 2026**

Pick of the Day ledger adds the published\_after\_kickoff withdrawal reason

[`GET /api/v1/pick-of-the-day/ledger`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger) and [`GET /api/v1/pick-of-the-day/ledger/{pick_id}`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger-entry) can now return a second value in `withdrawal_reason`: `published_after_kickoff`.

It marks a pick that was published at or after its game started, so it was never a pre-game pick. That includes a suspended match that resumed later, where the scheduled start moved to the resumption. The site's record leaves such a pick out of every count and money figure, the same as a `provider_game_cancelled` pick.

* The field's values are now `provider_game_cancelled`, `published_after_kickoff` or `null`.
* A `provider_game_cancelled` withdrawal happens while the pick is pending. A `published_after_kickoff` withdrawal can reach a pick that has already settled, so an entry's `withdrawal_reason` can change from `null` to `published_after_kickoff` after you first read it.
* The withdrawn pick keeps its commitment and its real outcome in the ledger. The field is not part of the hashed `payload`, so no `commitment_hash` changes.

**Backward compatible for most clients.** No field is added, removed or retyped. A client that validates `withdrawal_reason` against a closed list must accept the new value.

**What to change:** If you rebuild the track record from the ledger, keep skipping every entry whose `withdrawal_reason` is not `null`, and re-read settled entries instead of caching their `withdrawal_reason` at settlement.

**October 17, 2026**

Edge Hunter wider\_holder observations follow the kickoff order, soonest first

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations&cohort=wider_holder` now evaluates each sport's markets in kickoff order, soonest first. Among markets with the same kickoff, the market with the most graded holders comes first. A pre-game market that is evaluated stays evaluated until its game starts.

Before this change, each sport's 8 `wider_holder` slots went to the markets with the most graded holders in the whole 48-hour window. A market seen a day before kickoff could drop out when a later game with more holders entered the window, and be missing at its own kickoff.

* The limits stay the same: at most 8 markets per sport and cohort, 4 per event, and 168 in all. Markets beyond them still count in `coverage.capacity_limited_markets`.
* `in_play` keeps its order, most graded holders first.
* A market that enters the signals view's admission leaves `wider_holder`, as before. `view=signals` lists it only while its holder pile leans to one side, its backed side has a holder at or above `min_grade`, and its kickoff is within `horizon_hours`. The cohort description now says so.

**Backward compatible.** Fields, parameters, and limits do not change.

**What to change:** Nothing. To follow a market after it leaves `wider_holder` before kickoff, also read `view=signals` with `horizon_hours=48`.

**October 17, 2026**

Pick of the Day ledger says which settled picks the site withdrew

[`GET /api/v1/pick-of-the-day/ledger`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger) and [`GET /api/v1/pick-of-the-day/ledger/{pick_id}`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-ledger-entry) now add `withdrawal_reason` to every settled entry. It reads `provider_game_cancelled` when the site withdrew the pick because Polymarket marked its game Cancelled, and `null` when the pick counts in the record.

Before this change, the ledger did not say whether a pick was withdrawn. A withdrawn void and a counted void looked the same, so a client could not reproduce the site's record from the ledger.

* `opened` entries always carry `withdrawal_reason`.
* `uncommitted` entries carry it once the pick settles, and omit it while the pick is pending, the same way they omit `matchup`.
* `sealed` entries do not carry it.
* A withdrawn pick keeps its commitment and its real outcome in the ledger. The site's record leaves it out of every count and money figure.
* The field is not part of the hashed `payload`, so no `commitment_hash` changes.

To match the site's money at a flat stake, value each counted pick this way: a win returns `stake / backed_price`, a loss returns 0, and a void returns `stake * 0.5 / backed_price`. Leave a withdrawn pick out.

**Backward compatible.** One field is added. No field is removed or retyped.

**What to change:** Nothing, unless you rebuild the track record from the ledger. Then skip every entry whose `withdrawal_reason` is not `null`.

**October 17, 2026**

Explore markets states how old each sharp-money split is, as sharp\_money\_as\_of

[`GET /api/v1/markets/explore`](https://docs.0xinsider.com/api-reference/endpoint/explore-markets) now sends `sharp_money_as_of` on every market: when the oldest stored smart-money wallet behind the split in `smart_score`, `smart_count` and `smart_label` last finished syncing, and `null` when there is no split or a wallet's sync time is unknown. Some holdings in the split can come from a Polymarket holder read cached for up to 3 minutes, which this time does not describe.

Before this change the split carried no age, so it read as current. Graded wallets sync on different schedules, and most splits rest on positions that are days old: on October 17, 2026 the oldest position behind a market's split had a median age of 145 hours.

**Backward compatible.** The field is new, and the split itself is unchanged.

**What to change:** Nothing. To treat the split as recent, check `sharp_money_as_of` against your own bound; `null` never means current.

**October 17, 2026**

Pick of the Day values a void pick at the 50-50 payout, not a refund

[`GET /api/v1/pick-of-the-day/archive`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-archive) now values a pick that settled `void` at Polymarket's real payout. Polymarket settles a void market 50-50 and pays \$0.50 a share, so a void returns `stake_usd * 0.5 / backed_price`.

Before this change, the archive valued a void as if the stake were refunded. A pick bought at 0.64 then read as $0 profit, but the market paid $781.25 on a $1,000 stake, a loss of $218.75.

* `picks[].return_usd` is `stake_usd * 0.5 / backed_price` for a void, and `picks[].return_per_100` is `50 / backed_price`. Both are omitted for a void with no frozen price.
* `hit_rate.net_profit_usd`, `hit_rate.staked_usd`, `hit_rate.roi_pct`, and `days[].unit_score` now include a priced void. A void still counts in `void`, never in `wins`, `losses`, or `decided`, so `hit_rate.pct` does not change.
* `hit_rate.series[]` adds one point for a priced void. The point moves the profit and leaves the win rate unchanged.

No pick in the record was counted as a void when this shipped, so no value served today changes.

**Backward compatible.** No field is added, removed, or retyped. The values for a future void are corrected.

**What to change:** Nothing, unless your client computes its own return for a void. Value it at `stake * 0.5 / backed_price`.

**October 17, 2026**

Games that Polymarket has suspended now read as suspended, not live

[`GET /api/v1/games`](https://docs.0xinsider.com/api-reference/endpoint/list-games) and [`GET /api/v1/games/{event_slug}`](https://docs.0xinsider.com/api-reference/endpoint/get-game) now report a game that Polymarket has suspended, whose period reads `SUS`, with `status.state` `suspended`, `status.match_status` `suspended`, and `status.live` `false`. A request with `status=live` no longer returns such a game, and `status=suspended` does.

Before this change, these endpoints reported a suspended game with `status.state` `live` and `status.live` `true`, because Polymarket keeps a suspended game's in-play flag set. On October 17, 2026, two soccer games suspended on October 10 still read `live`.

* `status.period` still reads `SUS`, and the score is the last one Polymarket sent.
* The game reads `live` again when play resumes and its period moves on.
* `freshness.source` reads `upcoming` for a suspended game.
* The `status.live` description now names the two cases where the field differs from Polymarket's own flag: a suspended game, and a game rescheduled to a later kickoff, both read `false`.

**Backward compatible.** No field is added, removed, or retyped, and `suspended` was already a documented value of `status.state` and `status.match_status`.

**What to change:** Nothing, if your client already handles `suspended`. If you list live games with `status=live`, also request `status=suspended` to see games that stopped during play.

**October 17, 2026**

Market holders keep an empty answer for up to an hour while the market has no trades

[`GET /api/v1/market/{condition_id}/holders`](https://docs.0xinsider.com/api-reference/endpoint/get-market-holders) now keeps an answer whose scan found no wallet at all (`scan.wallet_count` is `0`), on an open market before its end date, for up to an hour while no trade in that market is seen after the scan. A trade, the market closing, resolving or passing its end date, or the hour ending stops the hold, and the next request scans again. The kept answer carries `meta.cached: true`, and `meta.cache_age_s` can now reach 3,600 seconds for these markets.

Before this change, every answer was recomputed at least once a minute, so `meta.cache_age_s` stayed under 60 seconds, over a Polymarket scan at most 180 seconds old.

* Shares that reach an empty market without a trade (a split, a merge or a transfer) can show up to an hour late.
* An answer whose scan saw any wallet, graded or not, keeps the one-minute refresh.

**Backward compatible.** No field is added, removed, or retyped.

**What to change:** Nothing. Read `meta.cache_age_s` for the age of an empty answer; the first trade in the market refreshes it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.