> ## 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: November 3, 2026

> 19 API, SDK, CLI, MCP, OAuth, and feed changes from November 3, 2026, newest first, each with its effect on clients. Newer changes are on the API changelog.

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

**November 3, 2026**

Leaderboard adds summary: ranked wallets, the S, A and B split, and 30-day active count

[`GET /api/v1/leaderboard`](https://docs.0xinsider.com/api-reference/endpoint/get-leaderboard) now sends a top-level `summary` with the whole board's totals, the counts the [leaderboard page](https://0xinsider.com/skill-leaderboard) shows. The `get_leaderboard` MCP tool returns it too.

Before this change, the only way to count the board was to walk every page.

* `ranked_total`: ranked wallets on the board.
* `by_grade`: the `S`, `A` and `B` counts, which sum to `ranked_total`.
* `active_30d`: wallets whose last trade was 30 days or less before `as_of`, the wallets `activity=active` lists.
* `as_of`: when the totals were counted.
* Sent on every page with no `category` and no `strategy`, whatever the `sort`, `dir` and `activity`. Left out on a `category` or `strategy` page, which lists a subset these totals do not describe, and while the ranking has no totals for the page's generation.

**Backward compatible.** Additive field; the entries, cursor and `meta` are unchanged.

**What to change:** Nothing. To read the board's size or grade split, read `summary` from any unfiltered page, for example `?limit=1`.

**November 3, 2026**

Webhooks now send an event about a second after it happens, not up to 10 seconds later

[Webhooks](https://docs.0xinsider.com/api-reference/endpoint/create-webhook.md) now start delivering an event as soon as it is recorded. In a local measurement of 7 events, an event reached the receiver a median of 0.35 seconds after it was recorded, and at most 1.5 seconds.

Before this change, a webhook sender with nothing to send checked for new events every 10 seconds. On November 3, `large_trade_inserted_v2` deliveries were created 5.5 to 9.3 seconds after the same trade reached [`GET /api/v1/stream`](https://docs.0xinsider.com/api-reference/endpoint/get-stream).

* A redelivery from [`POST /api/v1/webhooks/{id}/deliveries/{delivery_id}/redeliver`](https://docs.0xinsider.com/api-reference/endpoint/redeliver-webhook-delivery) starts at once too.
* Retries keep their schedule, and the 10-second check stays as a backstop.

**Backward compatible.** Payloads, headers, signatures and retries are unchanged.

**What to change:** Nothing.

**November 3, 2026**

Pick of the Day reads take view=summary, pick\_id, archive paging and stats sections

[`GET /api/v1/pick-of-the-day`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day), [`/archive`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-archive) and [`/stats`](https://docs.0xinsider.com/api-reference/endpoint/get-pick-of-the-day-stats) now take optional parameters that return a smaller body. The remote MCP tools `get_pick_of_the_day`, `get_pick_of_the_day_archive` and `get_pick_of_the_day_stats` now send `view=summary` unless you name a view.

Before this change, each read returned the whole record. On November 3, 2026 that was 198,807 bytes for one day's 14 picks, 1,124,089 for the archive and 151,774 for the stats. Claude Code saves an MCP result over 50,000 characters to a file instead of showing it, so an agent got no numbers.

* `view=summary` on the pick returns each pick's identity, side, price, result, return and grade, about 600 bytes a pick. `pick_id` returns one pick, and the MCP tool reads it in full by default.
* `view=summary` on the archive returns `hit_rate` without `series` and 50 short rows. `limit` (1 to 200) and `cursor` (from `page.next_cursor`) page the rows in either view and add `page`.
* `view=summary` on the stats leaves out `series`, `days`, `categories`, `months` and `voids`, the sections that grow with the record. `sections` returns only the sections you name, with `series` as its own key.
* An unknown `view` or `sections` name or a `cursor` the route did not return is `400 bad_request` with `error.param` naming it. `limit` behaves like every list limit: a value outside 1 to 200 is clamped, and one that is not an integer is `400 invalid_query`.

`@0xinsider/mcp` 3.12.0 has the same tools and defaults. Its release is pending; 3.11.0 and earlier still send no view.

`@0xinsider/sdk` 0.38.0 types the new parameters. It types the archive and stats `data` as the full body or the smaller one, so TypeScript code that reads them checks `"view" in data` first; the full body has no `view` key. Its release is also pending.

**Backward compatible** for REST. A request without the new parameters gets the same body and ETag. **Breaking** for remote MCP clients that read fields the summary leaves out, such as `display_holders` or `entry_authorization`.

**What to change:** Over MCP, send `view: "full"`, or call `get_pick_of_the_day` with `pick_id` for one pick in full. Over REST, nothing.

**November 3, 2026**

Edge Hunter reads category=sports as kind=sports in every view

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) now reads `category=sports`, in any casing, as `kind=sports` (every sport except Esports) in the board, signals and observations views, and in the MCP `get_edge_hunter` tool. The response's `selection` carries `kind: "sports"` beside `category: "sports"`. This matches the meaning `category=sports` has on every other route.

Before this change, `sports` was not a sport name, so it answered an empty result with `selection.category` set to `non_sport`.

* `category=sports` together with `kind=esports` now returns `400` with `param: "category"`, because the two select nothing in common.
* Any other category that is not a sport still returns an empty result with `category: "non_sport"`.

**Breaking** only for clients that send `category=sports` with `kind=esports`, which now get `400` instead of an empty result. Every other request that answered empty now answers the sports rows.

**What to change:** Nothing. Use `kind=sports` or `category=sports` for every sport except Esports, and do not send `category=sports` with `kind=esports`.

**November 3, 2026**

category=sports now matches every sport but Esports, not just the catch-all Sports

`category=sports`, in any casing, now matches every sport except Esports on [`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), their `whale-trades` aliases, [`GET /api/v1/leaderboard`](https://docs.0xinsider.com/api-reference/endpoint/get-leaderboard), [`GET /api/v1/markets/explore`](https://docs.0xinsider.com/api-reference/endpoint/explore-markets), [`GET /api/v1/markets/sharp-money-flows`](https://docs.0xinsider.com/api-reference/endpoint/sharp-money-flows) and its `smart-money-flows` alias, and [`GET /api/v1/trader/{address}/categories`](https://docs.0xinsider.com/api-reference/endpoint/get-trader-category-records). The MCP tools on those routes match the same way. The set includes `Sports`, the category Polymarket uses for sports with no category of their own, such as cycling and lacrosse.

Before this change, `sports` matched only that `Sports` category. Its newest large trade was from July 9, 2026, so `category=sports` on large trades answered with July trades as the newest, and history and leaderboard reads answered an empty page.

* [`GET /api/v1/positions`](https://docs.0xinsider.com/api-reference/endpoint/get-positions), [`GET /api/v1/large-positions`](https://docs.0xinsider.com/api-reference/endpoint/list-large-positions) and [`GET /api/v1/markets/search`](https://docs.0xinsider.com/api-reference/endpoint/search-markets) filter by one category, so `sports` now returns `400` with `param: "category"` there. Before this change it returned an empty list, and `Sports` returned that category alone.
* [`GET /api/v1/leaderboard`](https://docs.0xinsider.com/api-reference/endpoint/get-leaderboard) now matches every sport name in any casing. Before this change, `cricket` returned an empty page and only `Cricket` matched.
* A leaderboard cursor taken with `category=Sports` now returns `400 cursor_expired`, because the filter means a different set of wallets.
* On market explore, the `Sports` value in `facets.categories` still counts the catch-all category alone.

**Breaking** for clients that send `category=Sports` to read the catch-all category alone. That category can no longer be selected on its own.

**What to change:** Send `sports` for every sport except Esports, `esports` for Esports, or omit `category` for both. On positions, large positions and market search, omit `category` or name one sport, and handle `400` on the parameter.

**November 3, 2026**

A filtered stream resumes with Last-Event-ID after a short restart or a backend release instead of resyncing

[`GET /api/v1/stream`](https://docs.0xinsider.com/api-reference/endpoint/get-stream) now keeps a filtered connection's position on the server while it drops frames its filter excludes. A reconnect that sends the last `id` you received replays from where the connection stopped.

Before this change, a filtered connection usually answered `event: resync` with `completeness.status: "truncated"` on reconnect, even after a one-second restart. The replay window holds the newest 4,096 feed events of every type, about 15 to 30 seconds in the evening, and the last `id` a filtered client receives (for example `event=LargeTradeInsertedV2` with `min_size`) is often minutes older. Every backend release closes open streams, so a filtered client resynced on every release.

* The window itself is unchanged and is now stated in the endpoint description: it is counted in all feed events, not in the frames you receive.
* A client away longer than the window still gets a `truncated` resync. Catch up large trades with [`GET /api/v1/large-trades?since=`](https://docs.0xinsider.com/api-reference/endpoint/get-large-trades) or [`GET /api/v1/events/feed/since`](https://docs.0xinsider.com/api-reference/endpoint/get-event-replay-since).
* The wire format does not change: no new frame type, header or parameter.

**Backward compatible.** Every client benefits as it is, including `@0xinsider/sdk` 0.36 and a browser `EventSource`.

**What to change:** Nothing. Keep sending `Last-Event-ID` with the last `id` you processed.

**November 3, 2026**

SDK 0.37.0 sends the stream's wallet and min\_size filters

`@0xinsider/sdk` 0.37.0 adds `wallet` and `min_size` to `StreamFilters`, so `streamFeed`, `streamFeedResilient` and `consumeStreamCheckpointed` can send the [`GET /api/v1/stream`](https://docs.0xinsider.com/api-reference/endpoint/get-stream) filters of the same names.

Before this release, the SDK could send only `event`, `condition_id` and `min_grade`. A whale-alert consumer received every large trade and dropped small ones itself, and could not follow one wallet on the stream.

* `wallet` is a `0x` address in any case. `min_size` is a USD notional floor, `number | string`; pass a string such as `"25000"` to send it exactly.
* Both narrow `LargeTradeInsertedV2` frames. With either set, every other frame type is excluded, as on the endpoint.
* A malformed value is refused with `400` `bad_request` and `param` naming the filter; the resilient consumers do not retry it.

**Backward compatible.** Both fields are optional, and no existing filter changes.

**What to change:** Upgrade to 0.37.0 and pass `wallet` or `min_size` instead of filtering large trades in your handler.

**November 3, 2026**

Trader breakdowns state which settled positions the entry-price buckets leave out

`entry_price_analysis` in [`GET /api/v1/trader/{address}`](https://docs.0xinsider.com/api-reference/endpoint/get-trader) with `expand=breakdowns` now carries `coverage`, and the first entry-price band starts at \$0.

Before this change, the buckets left out every settled position with no single entry price and said nothing about it. On one wallet they held 9,121 of 12,811 settled markets, and $2.99M of the $5.79M those markets made, and a client reading them beside `pnl.in_scope` could take them for the whole record.

* `coverage` carries `settled_markets` and `settled_pnl` (every settled sports and esports position the section reads), `bucketed_markets` and `bucketed_pnl` (the buckets' sums), and `unbucketed`, one row per reason with `markets` and `total_pnl`. The bucketed and unbucketed markets add up to `settled_markets`.
* `reason` is `two_sided` (both outcomes bought, a hedged position with no single side), `held_side_unpriced` (the outcome the wallet held has no recorded price), `no_entry_price` (no outcome has one), or `freshness_unknown` (a bucket whose data has no freshness time yet).
* `settled_pnl` adds up the wallet's per-market realized P\&L. It differs from `pnl.in_scope.realized_pnl`, which is Polymarket's published sports and esports P\&L with a share of the wallet's rebates.
* The first band is `$0.00-$0.19` instead of `$0.01-$0.19`, and now holds positions bought below \$0.01, which had no bucket before.
* The MCP `get_trader` tool, the OpenAPI document and the SDK types describe `coverage`.

**Backward compatible**, except for the first band's label. `coverage` is a new field, and every other band keeps its label.

**What to change:** If you match the band label `$0.01-$0.19`, match `$0.00-$0.19` instead. Read `coverage.unbucketed` before you compare the buckets' totals with `pnl.in_scope`.

**November 3, 2026**

Rust crate oxinsider 0.5.0 adds game sharp money, game holders, and 10 more operations

The [Rust crate](https://docs.0xinsider.com/integrations/rust-client.md) `oxinsider` 0.5.0 covers all 106 operations in the OpenAPI document. It adds `get_game_sharp_money`, `get_game_holders`, `list_game_markets`, `list_game_trades`, and 8 more methods.

Before this change, `oxinsider` 0.4.0 covered 94 operations. `ListGamesParams` had no `expand`, `Game` had no `sharp_money` or `volume`, and a `200` response did not return its `ETag`.

* New methods: `get_game_sharp_money`, `get_game_holders`, `list_game_markets`, `list_game_trades`, `get_market_top_holders`, `get_market_wallets_in_out`, `get_pick_of_the_day_stats`, `get_resolution_report`, `get_sport_leaderboard`, `list_category_leaders`, `get_category_leaderboard`, and `list_leaderboard_leagues`.
* `ListGamesParams::expand` takes `sharp_money`, and `Game` has `sharp_money` and `volume`.
* Each of the 55 operations whose `200` carries an `ETag` has a `..._with_etag` method, such as `list_games_with_etag`. It returns `Tagged { data, etag }`. Send `etag` as `if_none_match` on the next read.
* `get_game_holders` takes `condition_ids` as a `&[&str]` argument.

**Breaking** for code that reads fields the document now types as enums, such as `LeaderboardEntry.grade`, which is `Grade` instead of `String`. The other methods keep their signatures.

**What to change:** Run `cargo add oxinsider@0.5.0`. Where a field is now an enum, read it with `as_str()`.

**November 3, 2026**

Game holders returns a market's last holder list, marked stale, while a fresh one computes

[`GET /api/v1/games/{event_slug}/holders`](https://docs.0xinsider.com/api-reference/endpoint/get-game-holders) and the MCP `get_game_holders` tool now answer a market whose fresh holder list is not ready within the request with the last list computed for it in the past 15 minutes. That item carries `stale: true` and its own `computed_at`.

Before this change, such a market was a per-item error with `reason` `read_model_warming`, even when [`GET /api/v1/market/{condition_id}/holders`](https://docs.0xinsider.com/api-reference/endpoint/get-market-holders) had served it minutes earlier. A cold holder scan takes longer than the batch can wait: on November 3 it took a median of 0.8 seconds and up to 13 seconds.

* Every item now has `stale`. It is `false` on a fresh list and `true` on the last list, which can be up to 15 minutes old.
* The fresh list keeps computing, so a read a few seconds after a `stale` item normally returns `stale: false`.
* A market refused over the account's cold-read share is served its last list the same way. It is a per-item `cold_read_limited` error only when it has none.
* A market with no list in the past 15 minutes is still a per-item error with `reason` `read_model_warming` and `retry_at`. Its `code` stays `rate_limit_unavailable` for compatibility, so branch on `reason`.

**Backward compatible.** `stale` is a new field, and no existing field changes meaning.

**What to change:** Nothing. Read `stale` and `computed_at` if your client needs holders newer than 15 minutes, and read the market again a few seconds later for the fresh list.

**November 3, 2026**

Go client v0.6.0 decodes every number as float64, so money keeps its cents

The [Go client](https://docs.0xinsider.com/integrations/go-client.md) `github.com/0xinsider/0xinsider-go` v0.6.0 decodes every JSON number as `float64`. Money and price fields such as `LargeTrade.SizeUsd`, `LargeTrade.Price`, and `GameSharpMoney.TotalUsd` keep the precision the API sends.

Before this change, 478 fields decoded as `float32`. Above $262,144 a `float32` cannot hold every cent: a trade the API sent as `351389.57` decoded as `351389.5625` and printed as $351,389.56.

* Regenerated from the current OpenAPI document, 106 operations.
* The README and examples read `OXINSIDER_API_KEY`, the variable the TypeScript and Rust clients read. They read `OXI_API_KEY` before.
* `oxinsider.Version` and the `User-Agent` header say `0.6.0`. v0.5.0 through v0.5.2 sent `0.4.0`.

**Breaking** for Go code that declares `float32` variables or parameters for these fields. It no longer compiles.

**What to change:** Run `go get github.com/0xinsider/0xinsider-go@v0.6.0` and change those `float32` declarations to `float64`.

**November 3, 2026**

Sandbox games list sharp money and game market lists match the per-game routes

In the [sandbox](https://docs.0xinsider.com/sandbox.md), [`GET /api/v1/games`](https://docs.0xinsider.com/api-reference/endpoint/list-games) with `expand=sharp_money` now gives each game the same `sharp_money` body that `GET /api/v1/games/{event_slug}/sharp-money` returns for it. `GET /api/v1/games/{event_slug}/markets` lists only that game's markets.

Before this change, the first game in the sandbox list carried `sharp_money: null` and every other game a placeholder with `object: "sandbox"`. A game's market list also included markets from other sandbox games.

* Without `expand=sharp_money`, sandbox games carry no `sharp_money` field, as in the live API. With it, `meta.cost` rises by 3.
* The `sport` field of a sandbox game carries a sport, such as `Football` or `Basketball`, and no longer a league, such as `NFL`.
* The live API is unchanged.

**Backward compatible.** Response shapes are unchanged. Sandbox values now agree across routes.

**What to change:** Nothing.

**November 3, 2026**

Sandbox game routes answer about the game named in the path

In the [sandbox](https://docs.0xinsider.com/sandbox.md), [`GET /api/v1/games/{event_slug}`](https://docs.0xinsider.com/api-reference/endpoint/get-game) and its `markets`, `sharp-money`, `trades`, and `holders` routes now describe the game that `GET /api/v1/games` lists under that slug. A slug the sandbox list does not include returns `404 not_found` with the live API's message.

Before this change, each route returned its documented example for every slug. `listGames()` followed by `getGameSharpMoney()` on the listed Bills vs. Jets game returned Celtics vs. Magic outcomes.

* Sharp money uses the side labels from the game's own winner market. For `nfl-buf-nyj-2026-09-22`, that is "Buffalo Bills" and "New York Jets".
* Market slugs, outcome labels, and market titles name the requested game.
* A slug from a live example, such as `nba-bos-orl-2026-11-01`, is not a sandbox game and returns `404`. Use a slug from the sandbox's `GET /api/v1/games`.
* The live API is unchanged.

**Breaking** for sandbox clients that send a slug the sandbox list does not include. Those requests now get `404` instead of a sample `200`.

**What to change:** In the sandbox, take `event_slug` from `GET /api/v1/games`.

**November 3, 2026**

Trader adds the profile's Edge badge and its strategy breakdowns with expand=breakdowns

[`GET /api/v1/trader/{address}`](https://docs.0xinsider.com/api-reference/endpoint/get-trader) now returns `price_edge`, the wallet's edge over the price it paid, and takes `expand=breakdowns` for the measures on the wallet profile's Insights tab.

Before this change, neither was in the API: the Edge badge and these measures were on the profile page only.

* `price_edge` carries `markets`, `hit_rate`, `avg_price`, `edge` and `status`, as on [Leaderboard](https://docs.0xinsider.com/api-reference/endpoint/get-leaderboard.md). When `status` is `ranked`, `shrunk_edge` is the number the badge shows and the leaderboard ranks, with `field_average`, the average it is pulled toward. It is left out for a wallet with no settled sports or esports market of \$20 or more.
* `breakdowns` carries `hourly_performance` (by UTC hour), `time_breakdowns` (hold-time and four-hour bands), `risk_metrics` (position sizes and category `concentration`) and `entry_price_analysis` (five entry-price bands). It is computed on each request, so a wallet with a long history can take several seconds, and a read past 30 seconds answers `503` with `Retry-After`.
* [`POST /api/v1/traders/batch`](https://docs.0xinsider.com/api-reference/endpoint/batch-get-traders) refuses `expand=breakdowns` with `400` and `param: "expand"`.
* The MCP `get_trader` tool takes `breakdowns` in `expand`, and the OpenAPI document and SDK types describe both fields.

**Backward compatible.** Both fields are new, `breakdowns` is sent only when requested, and no existing field changes.

**What to change:** Nothing. Read `price_edge` for the edge, and request `expand=breakdowns` on single-wallet reads that need the strategy measures.

**November 3, 2026**

Webhooks dead-letter paid event deliveries while the account has an unpaid invoice

[Webhook deliveries](https://docs.0xinsider.com/api-reference/endpoint/list-webhook-deliveries.md) of a paid event type now move to `dead_letter` while the owning account has an unpaid invoice, with `last_error` set to `delivery owner has an overdue invoice (payment_overdue); pay it, then redeliver this delivery`. Free event types still deliver.

Before this change, those deliveries kept going out while the same account's API requests answered `402` with `error.reason` `payment_overdue`.

* Each refused delivery stays on [Webhook deliveries](https://docs.0xinsider.com/api-reference/endpoint/list-webhook-deliveries.md) for 7 days, so nothing is dropped without a record.
* After the invoice is paid, requeue each one with [Redeliver a webhook delivery](https://docs.0xinsider.com/api-reference/endpoint/redeliver-webhook-delivery.md), or catch up from [Event replay](https://docs.0xinsider.com/api-reference/endpoint/get-event-replay-since.md).
* Endpoint verification is refused for the account until it pays.

**Backward compatible.** `status` and `last_error` keep their meaning; the message is new.

**What to change:** If you match on `last_error`, handle the new message, and redeliver the refused deliveries once the invoice is paid.

**November 3, 2026**

@0xinsider/mcp 3.11.0 and @0xinsider/sdk 0.36.0 are published with the payment\_overdue 402

`@0xinsider/mcp` 3.11.0 and `@0xinsider/sdk` 0.36.0 are on npm. They carry the November 2 and 3 entries below.

* On a `402 payment_overdue`, the local MCP server's tool error ends "Pay the overdue invoice at [https://0xinsider.com/billing](https://0xinsider.com/billing)." and its error detail carries `billing_url`. On a lapsed plan it ends "Reactivate at [https://0xinsider.com/billing](https://0xinsider.com/billing)."
* The SDK's `SubscriptionRequiredError` adds `billingUrl` and `paymentOverdue`, and `API_ERROR_REASONS` lists `payment_overdue`.
* `get_edge_hunter` and the SDK take `admission: "most_held_48h_by_type"` with `market_types`.
* `list_games` and `get_game` describe a tennis game's `tournament`, and the SDK exports `GameTournament` and `GameTournamentLocation`.
* Tool descriptions and `max_age_s` accept the `stale` data quality status. The SDK's `assessDataQuality` passes a `stale` group that is within your `maxAgeMs`.
* `0xinsider api call batchGetTraders` and `batchGetMarketFlow` reload a stored session once on a `401`, as every GET already did.

The [CLI](https://docs.0xinsider.com/integrations/cli.md), [MCP](https://docs.0xinsider.com/integrations/mcp.md) and [introduction](https://docs.0xinsider.com/index.md) pages now install `@0xinsider/mcp@3.11.0`.

**Backward compatible.** Both releases add fields, values, types and messages. Nothing is removed or renamed. One behavior changes: SDK 0.35.0 failed a `stale` group in `assessDataQuality` as an unrecognized status, and 0.36.0 passes it when it is within `maxAgeMs`.

**What to change:** Run `npm install --global @0xinsider/mcp@3.11.0`, or change a client's `@0xinsider/mcp@3.10.0` argument to `@0xinsider/mcp@3.11.0`. Run `npm install @0xinsider/sdk@0.36.0` to read `billingUrl` and `paymentOverdue`. `0xinsider --version` prints `3.11.0` once the update is in place.

**November 3, 2026**

A key whose account has an unpaid invoice answers 402 payment\_overdue

Every `/api/v1` request made with a key whose account has an unpaid invoice now answers `402` with `error.code` `subscription_required`, the new `error.reason` `payment_overdue`, and the new `error.billing_url`. The remote MCP endpoint answers the same `402`, and `GET /api/v1/me` and `GET /api/v1/usage` still answer `200`.

Before this change, a key kept full Pro or Max access while Stripe retried a failed renewal payment, which can take weeks.

* `payment_overdue` means the latest subscription is `past_due` or `unpaid`. Paying the invoice at `billing_url` restores the same key with its settings; no new key is needed.
* `billing_url` is `https://0xinsider.com/billing`. It is present on every `subscription_required` error, including `subscription_inactive`.
* `@0xinsider/sdk` 0.36.0 adds `billingUrl` and `paymentOverdue` to `SubscriptionRequiredError`. `@0xinsider/mcp` 3.11.0 names the billing link in the tool error and the CLI message.
* A retry does not clear the error. Only a person paying the invoice does.

**Backward compatible.** The code and status are unchanged; the reason and field are additive.

**What to change:** Stop scheduled retries on `payment_overdue` and show `billing_url` to the account owner. If you already handle `subscription_required`, nothing.

**November 3, 2026**

Edge Hunter admission=most\_held\_48h\_by\_type ranks markets within each type

[`GET /api/v1/edge-hunter`](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter) with `view=observations&cohort=wider_holder` now takes `admission=most_held_48h_by_type` with `market_types`. It runs the `most_held_48h` rule within each type you name: per sport and per `market_context.market_type`, up to 8 markets with the most graded holders, at most 4 per event. The `get_edge_hunter` MCP tool takes the same value, and the SDK's `admission` and `admitted_by` types gain it in the next `@0xinsider/sdk` release.

Before this change, `admission=most_held_48h` ranked every market type together and `market_types` filtered the rows afterwards. A type whose markets hold fewer wallets than team-win markets could return no rows: Soccer `totals` returned none on November 3, 2026, from 286 candidates.

* Every row has `admitted_by: "most_held_48h_by_type"`, the response echoes `admission`, and it has no `departures`.
* `market_types` is required, each value 1 to 64 lowercase letters, digits or underscores. A missing or malformed value returns `400` with `error.param: "market_types"`.
* A sport and type pair nobody asked for in the last 30 minutes returns `503` `read_model_warming` with `Retry-After: 45` once, while the next snapshot computes it.
* The default response and `admission=most_held_48h` do not change.

**Backward compatible.** The value is new and opt-in.

**What to change:** Nothing. To get Soccer totals, call `admission=most_held_48h_by_type&market_types=totals&category=Soccer` and retry once after a `503`. See [Most-held selection by market type](https://docs.0xinsider.com/api-reference/endpoint/get-edge-hunter.md#most-held-selection-by-market-type).

**November 3, 2026**

Tennis games carry their tournament: tier, city, venue time zone, dates and draw

[`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 return `tournament` on a tennis game: the tournament edition its game page states, from 0xinsider's registry curated from official ATP, WTA and ITF pages. The `list_games` and `get_game` MCP tools and the CLI's `api call listGames` and `api call getGame` return it too.

Before this change, no V1 route, MCP tool or CLI command named a tennis game's tournament tier, place or local time. A client had only the competition label in `league`.

* `tournament` holds `label` (the provider competition label, verbatim), `tour` (`atp`, `wta` or `itf`), `draw`, `tier` (for example `ATP Masters 1000`, `ATP Challenger 50`, `ITF M15`), `location` (`city`, `country`, `country_code`), `timezone` (the venue's IANA zone), `edition_year`, `starts_on`, `ends_on`, `source_urls` and `checked_on`.
* `draw` is `qualification` when the label ends `, Qualification` and `main` for an unmarked ATP or WTA label. It is omitted for an unmarked ITF label, because Polymarket gives an ITF qualifying match the main draw's label.
* `tier`, `location` and `timezone` are omitted when no official page states them. `tournament` is omitted outside tennis, when the registry holds no single edition for the game, and on a finished game read after it leaves the live board.
* The SDK types gain `GameTournament` and `GameTournamentLocation` in the next `@0xinsider/sdk` release.

**Backward compatible.** The field is new and optional.

**What to change:** Nothing. To show a tennis match in venue time, format `scheduled_at` with `tournament.timezone`. See [Tennis tournament](https://docs.0xinsider.com/api-reference/endpoint/list-games.md#tennis-tournament).


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