Pro includes 250,000 API requests a month; pay as you go covers the rest
Every authenticated
/api/v1 request now counts against a monthly quota. Pro includes 250,000 requests per UTC calendar month, whatever your billing interval. Every authenticated response carries three new headers: X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (Unix seconds, the first instant of the next month).GET /api/v1/usage adds monthly_quota, with used, limit, remaining, reset_at, enforced_from, binding, and pay_as_you_go. Reading it spends nothing.From October 1, 2026, request 250,001 in a month answers 429 with error.code rate_limited and the new error.reason monthly_quota_exceeded, carrying Retry-After and error.retry_at set to the month’s reset. A refused request is not counted. The counter runs from September 21, and nothing is refused before October 1.Switch pay as you go on at 0xinsider.com/developers and requests over the quota keep answering. The excess bills at $0.20 per 1,000 requests on a monthly invoice to the card on the subscription, and binding reads false for that account.Backward compatible. A client that branches on error.code needs no change.What to change: If you retry on 429, read Retry-After first, because the monthly reset is days away rather than seconds. An email on September 21 announced 100,000 requests from November 1; the served contract is the one above.OAuth registration caps at 10 per IP every 10 minutes, and metadata documents at 64 KiB
POST /oauth/register now has its own per-IP budget: 10 registrations per 600 seconds, checked after the shared OAuth cap of 60 a minute. The eleventh answers 429 with error temporarily_unavailable and Retry-After: 600. Every other OAuth temporarily_unavailable keeps Retry-After: 60.A client ID metadata document (an https client_id with a path) is now limited to 64 KiB of decoded body, checked while it downloads, and a document over the limit is refused and never cached. At most 8 uncached documents are fetched at once per backend process.Past that capacity, device authorization answers 429 with Retry-After: 30. The browser consent preview and decision keep their 200 ok: false shape with error temporarily_unavailable. A registered client or a cached document does not use that capacity.Backward compatible. Open registration is unchanged and by design: RFC 7591, public clients only, PKCE S256 required, and an exact redirect_uri match at authorize and at the token endpoint.What to change: Nothing. A client registers once and keeps its client_id, so no working client meets the cap.List every graded holder of a market
Added
GET /api/v1/market/{condition_id}/holders: the graded holder roster of any Polymarket market, the same list a Pick of the Day shows for its market. It returns every S, A, or B wallet with open shares on either outcome, taken from a complete provider holder scan, ordered by current_value_usd descending. A wallet holding both outcomes is listed once, on its net side.Each holder carries shares, Polymarket’s own current_value_usd for that outcome, grade, category_win_rate and category_win_record in the market’s category, badges, and last_traded_at.- Filters:
outcome(yes,no,all),min_grade(S,A, orB, whileC,D, andFanswer400),limit, andcursor(mh_prefix). - The envelope carries
market,scan(source,complete, andwallet_count, which counts every wallet the scan saw, graded or not),totalsby side and grade, and an exacttotal. - The route takes the raw
condition_idor themkt_id, and supportsETagandIf-None-Match. - An incomplete or failed scan answers
503witherror.reasonread_model_warmingandRetry-After. You never get a short list instead.
GET /api/v1/positions ignored condition_id, and GET /api/v1/large-positions is a change feed with a $50,000 floor, so neither could answer this.Backward compatible. No existing route changes.What to change: Nothing.Get a wallet's win record in every category, and in every esports game
Added
GET /api/v1/trader/{address}/categories: one wallet’s record in every canonical category it has a settled market in, busiest first. These are the counts behind the Pick of the Day holder chips.- Each record carries
category,wins,decided,win_rate, andstatus(measuredornot_enough_data). - The envelope carries
basis(settled_markets_all_sizes),min_decided_for_win_rate(5), andcomputed_at. - A record under that floor keeps its counts, with
win_rateset tonull. - A category with no settled market is left out, never returned as a 0% record.
- A resolved trader with no record returns
records: []with200. An unknown address returns404. ?category=filters to one bucket through the same category rollup the rest of the API uses:soccer,EPL, andchampions leagueall reach Soccer, andfootballis American football.
Esports record gained games[]: the wallet’s record per esports title (LoL, CS2, Dota 2, Valorant, and 7 more), each with game, series_slug, wins, decided, win_rate, and status under the same floor. The titles are named as the holder entries name them.games is absent on every other category and on an Esports record with no title history, and the Esports row keeps the whole bucket’s counts.Game records fill in from the first daily rebuild on September 22.This record differs from category_strengths on GET /api/v1/trader/{address}?expand=categories, which uses a different measured sample for ranking context. Both field descriptions identify the different bases; use this endpoint for the plain settled record.Backward compatible. No existing route changes.What to change: Nothing.Esports holder entries name the game their win rate was measured in
Holder entries on
GET /api/v1/pick-of-the-day and GET /api/v1/market/{condition_id}/holders add category_win_rate_game on an esports market. It names the game that category_win_rate and category_win_record were measured in: LoL, CS2, Dota 2, Valorant, Call of Duty, Honor of Kings, Mobile Legends: Bang Bang, Overwatch, Rainbow Six Siege, Rocket League, or StarCraft II.- It is present when the wallet has at least 5 resolved markets in that game. The rate and record are then that game’s rather than the whole
Esportsbucket’s. - It is absent when the rate is the wallet’s whole Esports record, on every non-esports pick, and beside every status that is not
measured. - The payload-level
categorystaysEsportseither way.
category_win_rate_game when it is present, and with category when it is not.Pick of the Day archive publishes the price behind return_per_100 and both CLV operands
GET /api/v1/pick-of-the-day/archive rows add backed_price on exactly the rows that carry return_per_100, and clv_entry_price and clv_close_price on exactly the rows that carry clv_pct. On a win, 100 / backed_price equals return_per_100. A pending pick, and any pick whose backed side is withheld, still carries none of them, so no gate moved.clv_explanation on a measured row now names the entry before the close: Entry 0.635, close 0.705: CLV = (0.705 / 0.635 - 1) x 100 = +11.0%. The previous form printed the close first, and the arithmetic is unchanged.What backed_price means is now stated everywhere it appears: the Polymarket CLOB order book midpoint at release, written once at publication and never changed, not an executed fill. A buyer pays the ask rather than the midpoint, so an executed stake usually returns a little less than return_per_100.An API subscriber’s audit had concluded the return was computed off the close; it is not, and both operands now sit next to the result.What to change: If you parse clv_explanation, take the first number as the entry price.The commitment ledger carries the payload of settled pre-sealing picks
GET /api/v1/pick-of-the-day/ledger now returns payload on a settled uncommitted entry: the market, side, and price of a pick published before sealing began, in the same 8 fields and the same key order as an opened payload. It is not hashed, and the entry stays pre_commitment: true.Before this change, an uncommitted entry carried no payload at all. 248 of the 250 picks published by September 21 predate sealing, so without their payloads a mirror could only take them on trust.payload is null while the pick is pending, and on a settled pick whose stored row is missing one of those columns.Backward compatible. Sealed and opened entries are unchanged.What to change: Nothing.Positions accept condition_id, and a deep page returns as fast as the first
GET /api/v1/positions now honors condition_id, raw or as the mkt_ id, to scope the feed to one market. Combine it with min_size=0 for every reconciled position in that market. An unknown id returns [].Before this change, the parameter was parsed and then silently ignored. The get_positions MCP tool takes the same parameter.A deep cursor page now returns as fast as the first. Page 11 of category=Baseball at limit=100 took 3,707 ms and often timed out at 30 s; it now takes 866 ms. Rows and cursors are unchanged.Remote MCP and @0xinsider/mcp 2.1.0 add get_sports_edge_observations
POST /api/v1/mcp and the stdio package @0xinsider/mcp 2.1.0 add get_sports_edge_observations, which calls GET /api/v1/sports-edge-observations. tools/list now returns 35 tools.cohortis required:wider_holder,in_play, oremerging_pile.category,limit(1 to 100, default 20), andcursorare optional.- The result carries the route’s
snapshot_as_of,degraded, andfunnelnext todata,has_more, andnext_cursor.degraded: truemarks a page you should not read as healthy evidence.
Pick of the Day expands coverage to later games
GET /api/v1/pick-of-the-day can now include later games on the New York calendar date.Before this change, daily coverage could omit those games. A day can still have no published selection.Backward compatible. No field changed, and scheduled_picks and the archive keep their shape.What to change: Schedule your next request from the 404 pick_not_released response’s error.retry_at instead of assuming the day has ended at a fixed UTC hour.New endpoint: every Pick of the Day's pre-game commitment, opened once it settles
Added
GET /api/v1/pick-of-the-day/ledger: one entry per published (pick_date, pick_rank), ascending, in one of three states. The route needs an API key on a Pro account.sealedis a live pick. It carriescommitment_hash,commitment_algo(sha256(canonical_json(payload)||nonce)),sealed_at,kickoff, andpermalink, and nothing that states a side or a price.openedis a settled pick. It carries those fields pluscommitment_nonce, the canonicalpayloadthe hash was taken over (market, side,backed_priceas a decimal string, kickoff, date, rank),outcome,resolved_at,matchup, andcategory.uncommittedis a pick with no commitment, either published before the scheme existed or reaching kickoff unsealed. It is named rather than left out, and carriespre_commitment: true.
payload exactly as you received them, append commitment_nonce decoded from hex, and sha256 the result. It equals commitment_hash, because the payload is served byte for byte as it was hashed.A commitment is never written after kickoff, and never rewritten by an outcome correction.Backward compatible. The pick and archive routes are unchanged.What to change: Nothing.Large positions report each outcome on its own and list every holding
On
GET /api/v1/large-positions, total_size_usd and position_unrealized_pnl are now the provider’s value and unrealized P&L for the one outcome named by outcome_label and token_id. null means the provider supplied no value, not zero. event_total_value_usd is now null when the value of any other outcome in the same market is unknown.Before this change, a wallet holding both outcomes of a market had both outcomes’ combined value and P&L labelled as one outcome.Four fields are added, two of them required:combined_value_usdandcombined_unrealized_pnlare the wallet’s whole-market totals. They equal the per-outcome fields unlessis_two_sidedistrue, and the feed ranks by the combined value.is_two_sidedistruewhen the wallet holds both outcomes.holdings[]lists every outcome the wallet holds, each withoutcome_index,outcome_label,token_id,share_count,avg_entry_price,current_price,value_usd, andunrealized_pnl.holdings[0]restates the top-level per-outcome fields.
total_size_usd as the wallet’s exposure in a two-sided market, read combined_value_usd instead.Volume fields are USD cash volume, never Polymarket leaderboard shares
Three
/api/v1 fields had been carrying Polymarket’s share counts as dollars, and they now report USD cash volume. Polymarket’s v2 leaderboard reports volume in both-sides shares, and its own schema says the figure is never USD.On GET /api/v1/leaderboard/trending:window_volume_usdis now both-sides cash volume in USD, taken from Polymarket’s user-volume read, and it leaves therequiredset. It is omitted when Polymarket served no volume for that wallet, never returned as zero.window_volume_sharesis added and carries the leaderboard’s share figure.- Polymarket tracks volume in whole UTC days, so the USD window is the whole-day span that covers the window you asked for.
- The default
min_volume_usd=5000floor now compares dollars.
GET /api/v1/trader/{address} stats.total_volume, GET /api/v1/leaderboard volume, and the trader export’s provider_lifetime_volume are now full-history both-sides USD cash volume from a verified observation, and are omitted or null without one. A wallet’s figure is typically lower than before, because the previous number was a share count.What to change: If you treated window_volume_usd as always present, handle its absence. Field names and types are unchanged.Grades weigh the last 90 days, and counterparty participants carry last_traded_at
The wallet
grade that every /api/v1 response carries now weighs the wallet’s last 90 days beside its lifetime record. A wallet with no trade for 30 days holds no better than B, and no better than C past 120 days.Before this change, the only recency rule was a 365-day cliff, and the median B-graded wallet had last traded 56 days earlier.GET /api/v1/whale-trades/{id}/counterparties/executions and .../makers add last_traded_at on the taker and on each maker: the latest recorded trade time, across all markets, for the tracked trader whose grade is shown. It is omitted when that time is unavailable.Backward compatible. The grade field and its values are unchanged, and last_traded_at is new and optional.What to change: Nothing, but a client that filters on grade will see some wallets move down.OAuth registration now stores and enforces grant_types
POST /oauth/register now stores grant_types and enforces it. Omitting the field registers ["authorization_code", "refresh_token"]. Using a grant the client did not register answers unauthorized_client (400) at consent, at POST /oauth/device/code, and at POST /oauth/token.Before this change, the registration response echoed a grant_types the server neither stored nor checked.- The list must name
authorization_codeorurn:ietf:params:oauth:grant-type:device_code. - It may not be empty, and it may hold nothing outside
grant_types_supported. Each failure answersinvalid_client_metadata. - The response reports the stored list.
response_typesis["code"]only when the client holdsauthorization_codeand registered a redirect URI, and[]otherwise. - A client without
refresh_tokengets a token response with norefresh_tokenfield, and repeats its flow after the hour.
Pick of the Day holders carry the counts behind the category win rate
Holder entries on
GET /api/v1/pick-of-the-day add category_win_record, the two counts that category_win_rate is the ratio of. It is present only when category_win_rate_status is measured, and absent from payloads created before the field shipped.wins: resolved markets in the pick’s category that the wallet closed with a profit.decided: markets the wallet closed with a profit or a loss. A market that resolved at zero realized P&L counts in neither.
@0xinsider/mcp 2.0.0 adds a product CLI with browser login
@0xinsider/mcp 2.0.0 turns the existing executable into a product CLI. It adds login (approved in a browser, through the device authorization flow in the entry below), whoami, refresh, and logout, plus read commands backed by the SDK. The CLI page lists every command.The read commands paginate JSON up to a bound, keep the full response envelope, and exit nonzero when the result is incomplete. 2.0.1, released the same day, refreshes an expired or rotated access token between pages, so a long paginated read no longer fails partway.- 2.x needs Node 22 or newer.
- Stored sessions need macOS or Linux.
serve, and init keep their behavior.What to change: Nothing. If you upgrade to 2.x, check that you are on Node 22 or newer.Typed category evidence on the trader route and on Pick of the Day holders
GET /api/v1/trader/{address}?expand=categories adds category_records[] and category_skill_model beside the existing category_strengths. Each record holds forward-only evidence for one category, built from observed Polymarket taker fills.A record carries:status:live,insufficient,stale,unknown, ordegraded.canonical_categoryandas_of.independent_event_countandresolved_condition_count.edge_mean,edge_sd,edge_se,edge_lower_95, andbrier_event_avg.model_versionandtaxonomy_version.
status is insufficient, stale, unknown, or degraded is still returned, and it withholds the scores. The absence of a category is not proof of skill. status is category eligibility, not a letter grade, and the wallet’s global grade is unchanged.category_skill_model reports how ready the model is overall, read from the same snapshot.Holder entries on GET /api/v1/pick-of-the-day also gained optional category context in this release. Internal selection evidence was later removed from customer pick responses; refer to the current endpoint for the supported holder fields.Backward compatible. The new fields are optional, and the trader route omits them unless you ask for expand=categories.What to change: Nothing.Pick of the Day holders carry wallet badges
Holder entries on
GET /api/v1/pick-of-the-day add 5 badge fields. They are stamped at serve time from the wallet’s current trader record, so they are never frozen with the pick.wallet_age_days: the wallet’s age in days.is_new_wallet:truewhen the wallet’s first trade was under 30 days ago.markets_traded: how many distinct markets the wallet has traded.is_bot:trueat 10,000 or more distinct markets traded. That is a breadth rule, not proof of automation.x_username: the X handle on the wallet’s Polymarket profile, without the@.
GET /api/v1/me returns the account and credential a request authenticated as
Added
GET /api/v1/me. It returns the account the request authenticated as, in an account envelope: the account ID, the credential ID, the credential kind, and the approved scopes. A developer key reports null scopes.The response carries no email address and no token. The route uses the same paid-access check, read scope, usage accounting, and rate limits as every other read. The product CLI’s whoami command reads it.Backward compatible. It is a new endpoint.What to change: Nothing.OAuth adds the device authorization grant (RFC 8628)
OAuth now supports the device authorization grant, so an agent with no browser and no redirect receiver can hold a scoped, revocable 1-hour token instead of a pasted long-lived API key. Discovery at
/.well-known/oauth-authorization-server now lists device_authorization_endpoint as https://api.0xinsider.com/oauth/device/code, and adds urn:ietf:params:oauth:grant-type:device_code to grant_types_supported.POST /oauth/device/code takes the form fields client_id, optional scope (default read), and optional resource. It returns device_code, user_code, verification_uri, expires_in: 600, and interval: 5.- The person opens
verification_uri, signs in, enters theuser_code, reviews the account and the scopes, then approves or denies. Only an active Pro account can approve. - Your client polls
POST /oauth/tokenwithgrant_type,client_id, anddevice_code. authorization_pending,slow_down,access_denied, andexpired_tokenall come back as400. Each poll that arrives early adds 5 seconds to the interval, and adevice_codethat has already been used answersinvalid_grant.- The exchange gives the same scoped grant, refresh, and per-client revocation as the authorization-code flow.
- A device-only client can register at
POST /oauth/registerwithoutredirect_uris, and asks forresponse_types: [].
Remote MCP adds get_sports_edge_signals, plus a Markdown document per market
POST /api/v1/mcp and the stdio package add get_sports_edge_signals, which dispatches to GET /api/v1/sports-edge-signals. tools/list now returns 34 tools, and @0xinsider/mcp 1.3.1 serves the same catalog.The stdio get_trending_wallets now caps limit at 50 and keeps the gaps in the daily P&L curve, which matches V1 and the remote tool. Before this change it advertised a limit of 100 and filled those gaps with zeros.Added GET /api/v1/market/{condition_id}/context.md, a self-contained text/markdown evidence document for one market. It needs an API key, and it is rendered from the same typed data as the market snapshot, including that snapshot’s trust fields.- It carries the market’s identity, the outcome labels and tokens, cached quotes, liquidity, live sports, and per-source freshness or the reason a source is unavailable.
- Text that came from a provider is encoded as indented JSON, so it stays inert.
- The path accepts a raw
condition_idor anmkt_id. An unknown market returns404. - There is no
ETag. Use the snapshot route for conditional reads.
An API key in a ?token= query parameter is refused on every route
An API key sent as a
?token= query parameter is now refused on every route, with 401 invalid_api_key and the new error.reason api_key_in_query. Before this change, POST /api/v1/mcp and its GET event stream still accepted a key that way.The reason: a live key does not expire, and a URL is written to access logs, proxies, shell and browser history, and client config dumps.- When a request carries both the header and
?token=, the header is used and the request succeeds. initialize,ping, andtools/liststill need no credential. A request that puts a key in the URL is refused before it reaches them.- No working integration used the query form. Between September 4 and September 17, 2026 it recorded no accepted request.
invalid_api_key code is unchanged, so a client that branches on error.code needs no change.What to change: Send the key as Authorization: Bearer <key>. A client that can only take a URL can run the @0xinsider/mcp stdio package with the key in its environment instead.Refused requests report the per-IP rate-limit budget
A request that
/api/v1 refuses before it checks the key’s own limit now carries the per-IP bucket’s RateLimit-* and X-RateLimit-* headers. Before this change those responses carried no budget, so a client retrying a rejected key could not see how close it was to the per-IP limit.The responses that now carry the headers:401 invalid_api_key.402 subscription_required.403for a deleted account, and403 insufficient_scope.423for a locked account.- The authentication layer’s own
500and503responses. - The MCP handshake, which needs no credential.
Pick of the Day's CLV average is reported in percentage points
GET /api/v1/pick-of-the-day/archive adds hit_rate.clv_avg_pp and hit_rate.clv_avg_pp_display. Both hold the mean closing-line move in percentage points, (close - entry) * 100, for example "-0.1 pp".The existing clv_avg_pct is the mean of per-pick ratios, (close / entry - 1) * 100. A cheap entry moves that mean more than a favorite does. A pick at $0.05 that closes at $0.10 counts as +100%, while a pick at $0.90 that closes at $0.95 counts as +5.6%.The percentage-point average counts every pick on the same scale, and it is now the headline figure on 0xinsider.com.Both averages cover the same measured picks, and both are omitted until at least 5 of them exist. clv_avg_pct and clv_avg_display are unchanged.Backward compatible. The new fields are optional.What to change: Nothing. Read clv_avg_pp if you want the figure 0xinsider.com shows.Large trades carry their share of the market's volume
GET /api/v1/whale-trades, GET /api/v1/whale-trades/history, and GET /api/v1/whale-trades/{id} add the optional field market_volume_share. It is the fill’s size_usd divided by its market’s volume at the moment the trade was recorded.size_usd on its own cannot tell a large bet in a thin market from a routine one in a deep market. A $10,000 fill is 0.00005 of a $200M market and 0.125 of an $80,000 one.- The value is not capped at
1, because a fill larger than the market’s stored trailing volume is the case that matters most. - It is absent when the market carried no volume figure, and on trades recorded before September 16, 2026.
- It is never
0as a stand-in for a missing value.
A second venue removed: the API serves Polymarket only
0xinsider retired its second venue on September 8, 2026. Every V1 endpoint now serves Polymarket data only, and responses no longer contain that venue’s markets, trades, positions, or P&L.
GET /api/v1/platformsreturnsplatforms.polymarketonly. The retired venue’s key is gone.platformonGET /api/v1/whale-trades/history,GET /api/v1/markets/sharp-money-flows, andGET /api/v1/markets/smart-money-flowsacceptspolymarketorall, and both return Polymarket rows. Every other value returns400 bad_requestwitherror.param="platform".GET /api/v1/markets/explorestill acceptsplatformfor backward compatibility, and returns Polymarket markets for every value.GET /api/v1/market/{condition_id}/snapshotreturnsmarket.provideraspolymarket, andliquidity.last_priceis alwaysnull.
platform value other than polymarket or all.What to change: Drop the platform parameter, or send polymarket. Earlier entries in this changelog describe the API as it shipped on their date.Pick of the Day serves every ready pick while another pick's proof is pending
GET /api/v1/pick-of-the-day now answers 200 when at least one published pick has readable smart-money proof. picks carries the picks whose proof is readable, and the new proof_pending_picks array lists the rest with pick_rank, release_at, kickoff, and retry_at.Before this change, one published pick whose proof was not readable yet turned the whole day into 503 read_model_warming. On August 29 one pick’s holder snapshot lagged its publish, and the API withheld three fully proven picks for 14 minutes. The 503 now remains only when no published pick has readable proof.Backward compatible. The field is additive.What to change: Nothing. To fetch a pending pick, read again at its retry_at.Remote MCP adds two Pick of the Day tools
POST /api/v1/mcp adds 2 tools, and both take no arguments. get_pick_of_the_day dispatches to GET /api/v1/pick-of-the-day, and get_pick_of_the_day_archive to GET /api/v1/pick-of-the-day/archive. tools/list now returns 33 tools.A tool error from any remote tool now carries the V1 error.code, error.reason, and error.retry_at when the handler set them. Before the day’s pick is released, get_pick_of_the_day therefore reads 404 Not Found (not_found/pick_not_released): ... Not available before <retry_at>., so an agent can schedule the next call instead of polling.The stdio package @0xinsider/mcp 1.2.0 serves the same 33 tools.Backward compatible. Existing tools and REST routes are unchanged.What to change: Nothing.Pick of the Day's 404 retry_at accounts for newly available selections
GET /api/v1/pick-of-the-day now sets error.retry_at and Retry-After on a 404 pick_not_released to account for newly available selections as well as scheduled releases.Before this change, the value was the earliest scheduled slot’s release_at. A newly available pick could release earlier, so a client honoring the old value could miss its release.Until a pick releases, keep scheduling requests from the returned retry time.Backward compatible. The response shape is unchanged.What to change: Nothing. A client that schedules from retry_at keeps working.Pick of the Day lists the day's picks that have not released yet
GET /api/v1/pick-of-the-day adds scheduled_picks: the day’s selected picks that have not released yet, in pick_rank order.Each slot carries exactly 3 fields: pick_rank, release_at, and kickoff. The shape holds no matchup, category, side, price, or holder data before release, so the schedule can be shown without revealing a pick early.The field is present only while at least one unreleased slot remains, so its absence means the day is fully released.Backward compatible. The field is optional.What to change: Nothing. To plan your next read, request once at the earliest release_at instead of polling.@0xinsider/mcp 1.0.9 serves 29 tools locally, up from 6
@0xinsider/mcp 1.0.9 is on npm, the first release since 1.0.2 on April 14. The local stdio server goes from 6 tools to 29, the same set the hosted endpoint serves.- New tools: positions, position timeline (by wallet or by id), large positions, trending wallets, trader P&L, market explore, sharp-money flows, market snapshots, whale-trade history and single-trade lookup, batch trader and market-intel lookups, daily, weekly and monthly report snapshots, trader exports, webhook reads, and event replay.
get_smart_money_flowsstill works.- Whale-trade tools return
recorded_signal_score. inithides the API key as you type it, and prints a placeholder where a configuration to paste by hand would have shown the key.
POST /api/v1/mcp serves the same tools plus get_report and search_content, 31 in all.Backward compatible. The release adds tools.What to change: Nothing. Run npx -y @0xinsider/mcp init to set up or update. If an earlier init printed your key into output that was recorded or shared, rotate the key from Developers.Large trades carry the signal score captured when the trade was recorded
GET /api/v1/whale-trades, GET /api/v1/whale-trades/history, and GET /api/v1/whale-trades/{id} now return the optional field recorded_signal_score next to the existing signal_score.signal_scoreis the current score.recorded_signal_scoreis the score captured with the trade record. Use it in alerts, audits, and historical comparisons.- The recorded score exists only for trades recorded after this release. Older trades return
null.
Pick of the Day reports the availability of stored trader context
GET /api/v1/pick-of-the-day added optional metadata describing whether stored trader context was available to read. Before this change, missing context did not distinguish an absent record from an unavailable one.The metadata described recorded context, rather than live trader statistics or entry permission. This release also documented the existing trader context and display category.Backward compatible at release. The metadata was optional. Internal selection diagnostics were later removed from customer responses; use the currently documented pick fields.What to change: Read the current endpoint reference for the customer response contract.New observation-only endpoint for wider-holder and in-play sports markets
Added
GET /api/v1/sports-edge-observations, an Insider-tier endpoint that reports evidence on sports opportunities that do not enter the funded Sports Edge slate. Every row carries observation_only: true, provider and holder freshness fields, and an explicit directional status.Pick one cohort, which is required:wider_holdermeasures pre-game markets where the graded holders currently agree, even when no recent graded whale flow exists.in_playmeasures only games the provider confirms are live, and only when the holder and directional evidence is fresh.
capacity_limited describes a bounded response. It does not by itself mean that the snapshot is degraded.Omit category to evaluate all 14 observation sports. That registry includes Table Tennis and Pickleball, classified from provider-confirmed tags and kept separate from Tennis. The table-tennis, table tennis, and pickleball filters all resolve through the canonical taxonomy, and neither sport is in the 12-sport funded projection.Reading the response:- Every
200carries a required top-leveldegraded: boolean, the verdict for the whole snapshot. It covers both operational trouble and unknown completeness. - A healthy
wider_holderrequest can reuse a snapshot for about 180 seconds.in_playnever serves one older than about 30 seconds. - Conditional reads use a weak semantic
ETagover the stable part of the page, which includesnext_cursorand excludes the request-specificmeta. - A malformed typed query value returns the standard JSON
400 bad_requestenvelope. 503witherror.reason: "read_model_warming"means the route ran out of time before it had the data it needs. A later failure shows up instead as a degraded200, with the funnel filled in where possible.- The API’s outer 30-second transport timeout still returns a
408with an empty body, so check the status before you parse JSON.
GET /api/v1/sports-edge-signals, Pick of the Day, or any order executor.What to change: Nothing.Sports Edge covers Golf, Formula 1, NBA Summer League, CFL, and Boxing
GET /api/v1/sports-edge-signals and GET /api/v1/pick-of-the-day can now return eligible markets for Golf, Formula 1 and NASCAR, NBA Summer League, CFL, and Boxing.Polymarket sends only generic sports metadata for some of these markets. 0xinsider uses the provider tags to identify their sports categories. Racing and Boxing are now supported canonical buckets.Correction: an earlier version of this entry also named Table Tennis and Pickleball. The funded release did not admit either sport. Both are registered for observation-only evaluation through the endpoint added on July 14, and neither feeds funded signals or Pick of the Day.For the funded taxonomy changes in this release, an open market can adopt the corrected category on a provider refresh. Historical rows need a controlled refold, so they are not implied to have reclassified on their own.Backward compatible. No request or response shape changed, and no existing category was renamed.What to change: Nothing.New endpoint: ranked pre-game sports markets with graded money on one side
Added
GET /api/v1/sports-edge-signals, a ranked list of upcoming pre-game sports markets (moneyline and props) where graded S, A, and B smart money sits on one side. The server computes the whole list in one call.Each signal returns:- The side the graded money is on, and its CLOB
token_id. - The grade distribution on that side:
s_count,a_count, andb_count. - The dollar concentration:
sharp_pctandbacked_sharp_usd. - The market’s
game_start_time, which is kickoff. - A calculated backing score,
conviction_score.
200 carries an ETag, and it is cursor-paginated with the cursor fixed to one snapshot.Backward compatible. It is a new endpoint.What to change: Nothing.Pick of the Day returns 404 outside today's pick, and adds game_started
GET /api/v1/pick-of-the-day changes in 2 ways.The new boolean field game_started is true once the backed game’s kickoff has passed, which means the snapshotted pre-game price is no longer actionable. It is absent on a legacy pick with no stored kickoff, and you should treat that as not started.The is_locked description was corrected at the same time. It is a pre-release embargo flag, so it is effectively always false on a served pick. Use game_started for kickoff.The endpoint now returns 404 when today has no published pick yet, instead of serving the most recent prior day’s pick, which was often already settled. The response shape is unchanged and 404 was already a documented response. This conforms the endpoint to its “today’s Pick of the Day” contract, so an automated consumer never acts on a finished game.Prior picks stay available through the archive endpoint.Backward compatible. game_started is optional, and the behavior change is non-breaking.What to change: Nothing.Sandbox test-mode API keys removed; one live key class remains
Sandbox test-mode API keys (
oxi_sk_test_...) are removed. The API now has a single key class, oxi_sk_live_..., sent as Authorization: Bearer oxi_sk_live_.... It requires an active Insider subscription and always returns live data.There is no fixture or deterministic-data mode any more. Every request reads live data.Breaking for a client still authenticating with an oxi_sk_test_... key. Those requests fail.What to change: Generate a live key from your account’s API keys page, and switch your clients over before this release.Pick of the Day: a fixed 19:00 Europe/Berlin release and any sport
GET /api/v1/pick-of-the-day and its archive change behavior in 2 ways. No field was added, removed, or retyped, but 2 values now mean something different.release_at is now a fixed daily instant: 19:00 Europe/Berlin, every day, which is 19:00 CEST in summer and 19:00 CET in winter. It used to be a kickoff-relative time that moved with whichever game was picked. next_drop_deadline counts down to the same fixed instant.When no pick is available at the release slot, publication can happen later. On a thin day the actual publication can trail release_at by minutes to hours.The pick can now cover more sports and prop markets, expanding beyond the previously narrower set of categories.- Sports: soccer, tennis, baseball, basketball, hockey, MMA, cricket, golf, and esports.
- Prop markets: totals, spreads, and exact scores.
- Expect
categoryvalues beyondSoccerin the archive from now on.
Whale trades expose the traded outcome and its CLOB token id
Each whale trade on
GET /api/v1/whale-trades, /whale-trades/history, and /whale-trades/{id} now returns the traded outcome and that outcome’s Polymarket CLOB token_id. The outcome is the provider’s own label for the side the trade was on, for example Yes, No, or a team. The existing side, BUY or SELL, is unchanged.Before this change only BUY or SELL was exposed, so you could not tell which outcome a whale trade was on, or get that outcome’s on-chain token id.outcome is null only for a multi-outcome market, or a market that has not synced, with no stored label. A trade from the venue retired on September 8, 2026 carries its provider label in outcome, and only its token_id is null, because that venue had no CLOB token; see that entry.Backward compatible. Both fields are optional and nullable.What to change: Nothing.Every V1 YES/NO/outcome now carries its Polymarket CLOB token id
Reads that expose an outcome, a side, or a net-flow direction now also return that outcome’s Polymarket CLOB
token_id. You can go straight from a YES, NO, or outcome label to its on-chain ERC1155 asset id without a second lookup. Use it for order placement, per-token price history, and on-chain reconciliation.The value is a decimal string for a synced Polymarket market, and null when it is unavailable, for example on a market from the venue retired on September 8, 2026, or a market that has not synced yet. The key is always present, and it is never in a required set; see that entry.The endpoints that gained it:GET /api/v1/positions:token_idnext toside.GET /api/v1/large-positions:token_idnext tooutcome_label.GET /api/v1/market/{condition_id}/intelandPOST /api/v1/markets/intel/batch:token_idonsmart_money, next todirection, and on everysmart_money.top_positionsentry.GET /api/v1/markets/smart-money-flows:token_idonsmart_money, next todirection.GET /api/v1/trader/{address}/position-timelineandGET /api/v1/traders/{trader}/position-timeline:token_idnext tooutcome_side.GET /api/v1/markets/explore:token_id_yesandtoken_id_nonext tooutcome_yesandoutcome_no. These are CLOB token ids (decimal strings), and they are different from the integer Gamma idsoutcome_yes_provider_idandoutcome_no_provider_id.GET /api/v1/reports/daily,weekly, andmonthly:token_idon everytop_whale_tradesentry.
Pick of the Day archive adds a cumulative track-record series
GET /api/v1/pick-of-the-day/archive now returns hit_rate.series, the cumulative track record of the Pick of the Day. It is ready to chart without recomputing it on the client.Each element is one resolved pick, a win or a loss, in ascending pick_date order, and carries:date: the pick’s publish date, asYYYY-MM-DD.net_profit_usd: the running cumulative profit of a $100 stake on every resolved, priced pick through that date.hit_rate_pct: the running hit rate (wins divided by decided) through that date, to one decimal.
hit_rate.net_profit_usd and hit_rate.pct, so a chart of the series always ends exactly on the headline numbers. The array is empty until at least one pick has resolved.Backward compatible. Every existing hit_rate field is unchanged.What to change: Nothing.Trader quant_metrics is now a documented, fixed field set
GET /api/v1/trader/{address} and POST /api/v1/traders/batch now return a curated, documented quant_metrics object when you pass ?expand=quant_metrics. Before this change it was an unconstrained pass-through of internal metrics.When expanded, the object always carries these 9 fields. Each is a number or null, and null means insufficient trade history, never 0.copy_scoreandsmart_score: scores from 0 to 100.smart_scoresummarizes measured performance, andcopy_scoresummarizes how practical the wallet’s past strategy may be to follow.sharpe_30dandsharpe_7d: risk-adjusted return over the trailing 30 and 7 days.profit_factor: gross profit divided by gross loss, capped at 1,000.edge_consistency: how stable the trader’s edge is over time, from 0 to 1.sharpe_percentile,pf_percentile, andconsistency_percentile: cross-sectional ranks against all traders, from 0 to 100.
null.Breaking for a client that read a metric outside this list.What to change: Nothing, if you use only the 9 documented fields.New endpoint: ranked market discovery by smart-money net flow
Added
GET /api/v1/markets/smart-money-flows, a ranked discovery feed that answers where smart money is flowing before you know a condition_id.It ranks markets by absolute net flow from S, A, and B grade traders over a 1h, 4h, 24h, or 7d window, with platform, category, min_grade, and direction filters. Pagination uses an opaque cursor anchored to the first page’s as_of, so new whale trades do not reorder later pages.To look at a single market in detail, use GET /api/v1/market/{condition_id}/intel.Backward compatible. It is a new endpoint.What to change: Nothing.Remote MCP read parity, usage and caching headers, and round-trippable IDs
Remote MCP read parity.
POST /api/v1/mcp now exposes 21 tools through tools/list, covering the public V1 reads: batch reads, history, event replay, webhook reads, reports, market snapshots, and trader exports. Webhook mutations stay REST-only, and the endpoint is tools-only, with no resources and no prompts.Your own usage. Added GET /api/v1/usage, an authenticated read of your current per-minute limiter window and your UTC-day usage. It does not spend primary quota, but it has its own guard of 100 reads a minute.Cheaper polling, safe retries. Deterministic reads now support ETag and If-None-Match conditional GETs, so an unchanged read returns 304 with no body. Webhook create, update, delete, and rotate accept an Idempotency-Key.Discovery. Added GET /api/v1, an API discovery document, and GET /api/v1/openapi.json, a redirect to the canonical OpenAPI spec. Operation IDs are now codegen-friendly, with examples, code samples, and response-header metadata.Round-trippable IDs. Market Intel and Market Snapshot now accept either the mkt_... market ID or the raw condition_id. New GET /api/v1/whale-trades/{id} and GET /api/v1/insider-radar/{id} return a single wt_... or rf_... record. A prefix that is not a market prefix returns 400 bad_request.Backward compatible. Everything here is new or optional.What to change: Nothing.Remote MCP exposes position and market discovery tools
POST /api/v1/mcp now exposes 9 tools through tools/list. The new ones are get_positions, get_position_timeline, and explore_markets.Each dispatches to the existing public REST handler, so an MCP client gets the same auth, pagination, and payload contracts as a direct REST caller.New builder endpoints: batch, history, events, webhooks, reports, snapshots
Added task-shaped builder endpoints, so an integration needs fewer calls:
POST /api/v1/traders/batchPOST /api/v1/markets/intel/batchGET /api/v1/whale-trades/historyGET /api/v1/events/feed/sinceGET /api/v1/market/{condition_id}/snapshotGET /api/v1/reports/daily,weekly, andmonthlyGET /api/v1/trader/{address}/exportGET /api/v1/webhooks, plus webhook create, read, update, delete, verify, and rotate-secret operations
TypeScript client source added
Added TypeScript client guidance for the repo-owned client source in
web/src/lib/api-client.The client source is drift-tested against OpenAPI. It handles bearer auth, path params, repeated query params, JSON bodies, and V1 error envelopes. It is not a published npm package yet.Market Intel rejects prefixed market IDs
GET /api/v1/market/{condition_id}/intel now returns a clearer 400 bad_request when a caller passes a prefixed market.id value such as mkt_... instead of the raw condition_id.Call GET /api/v1/markets/search first, then pass the condition_id it returns into the Market Intel path.Trader lookup accepts usernames and plain expand params
GET /api/v1/trader/{address} now accepts a known trader username in the path, as well as an Ethereum wallet address.You can request heavy trader fields with repeated expand query params. The older expand[] form still works for existing clients.Leaderboard strategy fields can be null
GET /api/v1/leaderboard now returns traders that have no classified strategy.Treat strategy_type as nullable for a ranked trader with no strategy classification.Explore Markets excludes untitled rows
GET /api/v1/markets/explore no longer returns untitled markets.The response set is now titled, user-facing markets only.Trader realized P&L corrected
GET /api/v1/trader/{address} now returns the canonical realized P&L, read from the realized_pnl source-of-truth field.pnl.realized no longer derives realized P&L from an inconsistent approximation.Explore Markets endpoint launched
Added
GET /api/v1/markets/explore for cursor-paginated market discovery.It supports category, status, platform, and text filters. It also injects the primary market, so a grouped event includes its main market when one exists.Initial V1 launch
Launched the first public developer API:
GET /api/v1/trader/{address}GET /api/v1/whale-tradesGET /api/v1/leaderboardGET /api/v1/markets/searchGET /api/v1/market/{condition_id}/intelGET /api/v1/insider-radarGET /api/v1/health
expand[], cursor pagination, prefixed IDs, and rate-limit headers.Numeric precision standardized
Money values and scores are truncated to 2 decimal places across V1 responses.Prices and rates are truncated to 4 decimal places.