List endpoints for events and markets now return
events and markets arrays instead of a shared data field.
Detail endpoints now use separate paths for id-based and slug-based lookups.Breaking
GET /v1/polymarket/eventsnow returns{ events, nextCursor }.GET /v1/polymarket/marketsnow returns{ markets, nextCursor }.GET /v1/polymarket/events/{identifier}is replaced by/events/{event_id}for numeric ids and/events/slug/{event_slug}for slugs.GET /v1/polymarket/markets/{identifier}is replaced by/markets/{condition_id}for condition ids and/markets/slug/{market_slug}for slugs. Numeric market ids are no longer accepted by the public REST route.
Migration
- Replace
res.datawithres.eventsfor events lists. - Replace
res.datawithres.marketsfor markets lists. - Send event slugs to
/v1/polymarket/events/slug/{event_slug}. - Send market slugs to
/v1/polymarket/markets/slug/{market_slug}. - Keep condition ids on
/v1/polymarket/markets/{condition_id}.
Single-object endpoints no longer wrap their result in a
data field. This is a breaking change for any code that reads res.data on a single object.Changed
- Single objects return bare:
price,midpoint,spread,last-trade-price,orderbook,events/{id},markets/{id},auth/me, andPOST /auth/keys. Read fields at the top level (res.price, notres.data.price). datais now reserved for cursor-paged lists only (events,markets):{ data: [...], nextCursor }.GET /searchreturns the composite object bare:{ events, themes, profiles, pagination }.GET /auth/keysrenames its array fromdatatokeys:{ keys, plan, trialEndsAt, monthlyUsage }.- Error bodies use camelCase:
request_idis nowrequestId.
Migration
- Single object: replace
res.datawithres(or read the field directly). - Search: replace
res.datawithres. - Keys list: replace
res.datawithres.keys. - Errors: read
requestIdinstead ofrequest_id.
Markets are now a first-class endpoint group, mirroring events. Data comes from the Polymarket Gamma catalog.
Added
GET /v1/polymarket/markets— list markets, cursor-paginated.GET /v1/polymarket/markets/{identifier}— one market by condition id (0x…), numeric id, or slug.- Both are also exposed as the
list_marketsandget_marketMCP tools.
Public JWT keys let apps with no backend call Radion straight from the browser or a mobile client. A public key (
pk_jwt_...) is safe to ship, and each request also carries a signed end-user token. Separately, per-second rate limiting was removed from all paid plans.Added — public JWT keys
- A new key type,
pk_jwt_..., is safe to embed in a browser or mobile app. On its own it does nothing: every request must also send a signed user JWT in theAuthorization: Bearerheader. - Configure the key in the dashboard with a JWKS URL or an inline public key (PEM), plus optional
aud/isschecks and a per-user rate limit. - Radion verifies the JWT signature, checks
exp(andaud/isswhen set), and rate-limits per user (sub). Monthly usage still counts against your plan. - Tokens must use an asymmetric algorithm (
RS*,PS*,ES*, orEdDSA). Symmetric algorithms (HS256and friends) are rejected. - Browser WebSocket clients that cannot set headers may pass
api-keyandtokenas query parameters on the/wsupgrade. See Authentication.
Breaking
requestsPerSecondin theGET /auth/meresponse is nownullon paid plans. It stays a number on the free plan. Handle a nullable value.
The orderbook read model expanded from a single midpoint into full depth plus dedicated price endpoints. Search now paginates, events carry richer metadata, and two fields were removed.
Breaking — removed
GET /v1/polymarket/lookup. Use/searchfor fuzzy text search, or the id-scoped endpoints (/markets/{condition_id},/markets/slug/{market_slug}, and the trader endpoints by address) for exact reads.- The
expiresAtfield fromGET /auth/me. API keys do not expire.
Breaking — changed
GET /v1/polymarket/orderbooknow returns full depth instead of only the midpoint. The response holdsbidsandasksarrays of{ price, size }levels, pluslastTradePriceandtokenId. It still takestoken_id. Read the midpoint from the new/midpointendpoint.
Added
GET /v1/polymarket/midpoint— midpoint price for one outcome token. Takestoken_id.GET /v1/polymarket/price— bestbidoraskprice. Takestoken_idandside(buyorsell).GET /v1/polymarket/spread— bid-ask spread. Takestoken_id.GET /v1/polymarket/last-trade-price— last executed trade price. Takestoken_id.
Changed
GET /v1/polymarket/searchnow returns apaginationobject withhasMoreandtotalResults, and each profile includescreatedAt. Query params areq,limit, andpage.GET /v1/polymarket/eventsand/events/{identifier}now return enriched metadata:ticker,subtitle,resolutionSource,image,icon,featuredImage,subcategory,seriesSlug, theactive/closed/archived/new/featured/restrictedflags,enableOrderbook,negRisk,competitive,volume24hr/volume1wk/volume1mo/volume1yr,commentCount,creationDate,closedTime, and the fullmarketsarray.
Trader endpoints now enrich responses with live Polymarket data instead of placeholders.
Added
GET /v1/polymarket/traders/{trader_id}/profilenow returns a realidentity(pseudonym, name, x username, verified badge, account created at) from the trader’s Polymarket public profile.GET /v1/polymarket/traders/{trader_id}/themesnow returnsthemeLeaderboard,eliteThemes, andavoidThemesaggregated from market tags; each per-market entry now carries the marketslug.GET /v1/polymarket/traders/{trader_id}/edgenow fillsbestEdgeConditions.themes.
Breaking — removed
- The
warnings.themeDataUnavailablefield from the traderedgeandthemesresponses.
Radion now serves Polymarket data from its own on-chain indexer instead of stored analysis snapshots. The analysis and backtesting products were removed and replaced by direct read-model endpoints for markets, traders, events, search, and the orderbook.
Breaking — removed
GET /v1/polymarket/markets/analysisandGET /v1/polymarket/markets/{slug}/analysis.GET /v1/polymarket/traders/analysisandGET /v1/polymarket/traders/{id}/analysis.- All
/v1/polymarket/backtesting/copytrading/*endpoints. - Response schema (component) names dropped the
Dtosuffix, e.g.TradeDto→Trade. This affects code generated from the OpenAPI schema. - Every single-object response is now wrapped in a
datafield, so all endpoints share one shape.GET /traders/{trader_id}/pnl, market detail, market-by-slug, orderbook, search, and event endpoints used to return the object on its own; read the value fromdatanow.
Added
GET /v1/polymarket/markets— list markets by volume; plus/markets/{condition_id}and/markets/slug/{market_slug}.GET /v1/polymarket/markets/{condition_id}/candlestick,/holders, and/trades.GET /v1/polymarket/traders/{id}/trades,/positions, and/pnl.GET /v1/polymarket/traders/{id}/profile,/performance,/risk,/edge,/distribution, and/themes— rebuilt on the on-chain read model.identityfields arenulland theme grouping ships empty for now;/themesstill returns best/worst markets by realized PnL, keyed by condition id.GET /v1/polymarket/traders/global-pnl— PnL leaderboard.GET /v1/polymarket/eventsand/events/{identifier}.GET /v1/polymarket/search— venue-agnostic text search across events, topics, and profiles (proxied from Polymarket).GET /v1/polymarket/lookup— exact lookup of a market or trader by id (condition id or address). This is the old/searchbehaviour, renamed.GET /v1/polymarket/orderbook— live orderbook midpoint for one outcome token. The path isorderbook(one word, no hyphen) and takestoken_id, notposition_id.
Migration
- Replace analysis reads with the on-chain endpoints: market metadata via
/marketsand/events, trader data via/traders/{id}/pnl,/positions, and/trades. - Drop backtesting calls; the copytrading simulator is no longer offered.
- Regenerate any OpenAPI-derived client so schema names without the
Dtosuffix resolve. - Stop reading
traderScoreandconfidence.score/ratingfrom the performance response.
Request throttling moved from an hourly quota to a per-second token bucket. Monthly quotas are unchanged. The burst is keyed by your account and shared across all keys.
Breaking
- Hourly quotas are removed. Per-second rate limits are now Free: 5, Starter: 10, Pro: 50 requests/second. Enterprise stays uncapped.
GET /auth/me:hourlyLimitis renamed torequestsPerSecond.
Unchanged
- Monthly quotas remain Free: 300, Starter: 3,000, Pro: 50,000 requests/month, shared across all keys and reset at the start of each UTC month.
- Exceeding either limit still returns
429 Too Many Requestswith aRetry-Afterheader.
Win rate and PnL shared one field name across endpoints while measuring different things. Trader analysis is lifetime (includes resolved-but-unclaimed positions and unrealized PnL); performance is realized-only over a trailing 365-day window. Fields were renamed so one name never means two computations. Entry-bucket fields became structured objects instead of raw price arrays.
Breaking — field renames
GET /v1/polymarket/traders/{trader_id}/performance:winRate→trailing365WinRate,realizedPnl→realized365Pnl(both: closed positions, trailing 365 days).GET /v1/polymarket/traders/{trader_id}/analysisand the trader analyses list:winRate→lifetimeWinRate,profitLoss→lifetimePnl(both: lifetime),medianVolume→medianPositionSizeUsd(value unchanged).- Market analysis
topTraders[]:winRate→lifetimeWinRate,profitLoss→lifetimePnl(same lifetime basis).
Breaking — entry buckets
GET /v1/polymarket/traders/{trader_id}/distribution:sweetSpotBucket→sweetSpotBucketsanddeadZoneBucket→deadZoneBuckets. Both changed from a nullable price array (number[] | null) to a required array ofEntryBucketobjects.GET /v1/polymarket/backtesting/copytrading/jobs/{jobId}/summary:priceRange(number[] | null) → requiredbestBuckets(EntryBucket[]).EntryBucketobjects gained two required fields:realizedPnlandvolumeUsd.
Migration
- Update field reads to the new names. The two win rates and two PnL figures are not interchangeable — analysis values are lifetime (unclaimed + unrealized), performance values are realized over a trailing 365 days.
- Read
medianPositionSizeUsdinstead ofmedianVolume; value and units (USD) unchanged. - Read bucket fields as
EntryBucketobjects, not price numbers, and drop null handling — these fields are now always present.
Trader profile affinity now uses themes derived from Polymarket market tags instead of Polymarket’s legacy category field. The API naming changed from categories to themes.
Breaking
GET /v1/polymarket/traders/{trader_id}/categories→GET /v1/polymarket/traders/{trader_id}/themes.- Response types and fields renamed:
categoryLeaderboard→themeLeaderboard,eliteCategories→eliteThemes,avoidCategories→avoidThemes. - Leaderboard and ROI entries now expose
themeinstead ofcategory. - Warning field
categoryDataUnavailable→themeDataUnavailable. bestEdgeConditions.categories→bestEdgeConditions.themes.
Migration
- Call the
/themesendpoint for trader theme affinity. - Update clients to read
themeLeaderboard,eliteThemes,avoidThemes,theme, andthemeDataUnavailable. - Update edge consumers to read
bestEdgeConditions.themes.
API access now requires an API key on every endpoint except
GET /health. Dashboard key management supports multiple active keys, per-plan key caps, and shared monthly usage counters. Premium features are now enforced by plan.Breaking
- Unauthenticated API requests are no longer accepted. Send
X-API-Keyon every request exceptGET /health. - Plan names changed from
signal/agent/customtostarter/pro/enterprise. GET /auth/menow returnskeyLabelinstead ofkeyId, and may returnplan: nullfor Free keys.GET /v1/polymarket/markets/{slug}/analysisnow returns{ "data": [...] }. Withoutfrom, the array contains the latest snapshot as a single item.
Added
GET /auth/keys— list active keys for the signed-in dashboard user.POST /auth/keys— create a key with akeyLabel. The raw key is returned once asrawKey.DELETE /auth/keys/{keyLabel}— revoke an active key by label.GET /auth/meandGET /auth/keysnow expose monthly usage viamonthlyUsage.used,monthlyUsage.limit, andmonthlyUsage.resetsAt.GET /auth/mealso includeshourlyLimit.GET /v1/polymarket/markets/{slug}/analysis?from=YYYY-MM-DDreturns historical snapshots computed on or after the date.
Changed
- Hourly quotas are now Free: 50, Starter: 100, Pro: 1,000 requests, Enterprise: custom.
- Monthly quotas are now enforced: Free: 300, Starter: 3,000, Pro: 50,000 requests, Enterprise: unlimited.
- Monthly usage is shared across all keys for the same user. Extra keys do not create extra quota.
- Active key caps are Free: 1, Starter: 3, Pro: 10, Enterprise: unlimited.
POST /v1/polymarket/backtesting/copytrading/runnow requires Pro or Enterprise.- Historical market snapshots through the
fromparameter require Starter or higher. - Monthly quota exhaustion returns
429 Too Many Requestswithdetail: "Monthly request limit exceeded"and aRetry-Afterheader pointing to the next monthly reset.
Migration
- Create a free key from the dashboard and send it with
X-API-Keyon all API calls. - Update plan handling to use
starter,pro,enterprise, ornullfor Free keys. - Read
keyLabelinstead ofkeyIdfrom auth responses. - Update market-analysis-by-slug clients to read the first item of
datawhen they need only the latest snapshot.
Copytrading backtest jobs now continue when upstream price history is unavailable for individual tokens. Summary responses include warning metadata so you can detect degraded price-history coverage. The authenticated API key metadata endpoint was renamed to
GET /auth/me.Breaking
GET /auth/api-keywas removed. UseGET /auth/mewith the sameX-API-Keyheader instead.
Changed
GET /auth/mereturns the same API key metadata response shape thatGET /auth/api-keyreturned.GET /backtesting/copytrading/jobs/{jobId}/summary: completed jobs may include awarningsobject withmissingPriceHistoryTokenCount,totalTokenCount, andpriceHistoryCoveragePct.- If price history is missing for some tokens, open-position valuation may be less precise. The simulator continues with its fallback pricing instead of failing the whole job.
Example
API endpoints are now available under the
/v1 namespace. List endpoints use opaque cursor-based pagination. The copytrading backtest request field was renamed for multi-venue compatibility. All endpoints now validate input parameters and return structured errors on invalid input.Breaking
GET /markets/analysisandGET /traders/analysis: theoffsetparameter is removed. Usecursorinstead (omit on first request).- Response shape now includes
nextCursor:{ "data": [...], "nextCursor": "..." | null }. POST /backtesting/copytrading/run: request fieldtraderAddressesrenamed totraderIds. The Ethereum-address format constraint was removed — any non-empty string up to 256 characters is accepted, supporting non-Ethereum venues.
Changed
- Use
/v1as the canonical prefix for versioned analysis and backtesting requests, e.g.GET /v1/polymarket/markets/analysis. - Health and authentication endpoints stay at root:
GET /healthandGET /auth/api-key. - Existing unversioned routes such as
GET /markets/analysiscontinue to work for now. - All endpoints now validate input. Invalid values return
400 Bad Requestwith a structuredapplication/problem+jsonbody. GET /markets/{slug}/analysis:slugmust be 1–200 chars.GET /traders/{id}/analysis:idmust be non-empty, max 256 chars.GET /backtesting/copytrading/jobs/{jobId}/*:jobIdmust be a valid UUID.GET /markets/analysisandGET /traders/analysis: defaultlimitchanged from 50 to 5, maxlimitfrom 100 to 10.offsetis replaced by cursor-based pagination.
Deprecation notice
- Unversioned endpoints are backward-compatible aliases and will be removed on June 16, 2026.
Migration
- Update API clients to call analysis and backtesting endpoints under
/v1/polymarket. Generic/v1/markets,/v1/traders, and/v1/backtestingpaths are not served. - No request-body or response-body changes are required for the
/v1/polymarketmigration. - Remove
offsetfrom all requests to list endpoints. - Pass the
nextCursorvalue from each response as thecursorparameter on the next request. Stop whennextCursorisnull. - Update analysis list requests that set
limitabove 10. The default is now 5, and the maximum is now 10. - Rename
traderAddressestotraderIdsin allPOST /backtesting/copytrading/runrequest bodies.
Trader metrics fields were renamed and deduplicated for consistency across trader-analysis and market top-trader responses.
Changed
walletMedianVolumeon trader-analysis responses was renamed tomedianVolume. Value and type unchanged.- The redundant
positionCountfield was removed from market top-trader entries. It always duplicatedtotalPositionCount.
Migration
- Read
medianVolumeinstead ofwalletMedianVolumewherever you consume trader-analysis responses. - Read
totalPositionCountinstead ofpositionCounton market top-trader entries.
Market analysis responses now expose the canonical venue-scoped market identifier only at
market.id.Changed
- The top-level
marketConditionIdfield was removed from market-analysis responses. Usemarket.idinstead. - Request paths are unchanged. Continue to use market slugs in endpoints such as
GET /markets/{slug}/analysis.
Migration
Update clients to readmarket.id instead of marketConditionId.Before
After
Error responses now return a structured JSON body following RFC 9457.
Changed
- All error responses now return
type,status,title,detail, andrequest_idwithContent-Type: application/problem+json. - The
429 Too Many Requestsresponse still includes aRetry-Afterheader.
Migration
Update error handling to readdetail and request_id instead of a flat error string.Before
After
All API endpoints except
GET /health now enforce hourly request quotas. Unauthenticated requests are allowed and count against the free-tier quota, keyed by IP address.Quotas by plan
- Free (no key): 10 requests/hour, keyed by IP address.
- Signal: 100 requests/hour, keyed by API key.
- Agent: 1,000 requests/hour, keyed by API key.
- Custom: unlimited.
Behavior
- Your full hourly quota is available immediately as a burst, then replenishes continuously through the hour.
- Requests exceeding the quota receive
429 Too Many Requestswith aRetry-Afterheader.
The endpoints for creating on-demand analysis runs and checking their status were removed. Analysis snapshots are still available via the read endpoints.
Removed
POST /markets/{slug}/analysisGET /markets/{slug}/analysis/statusPOST /traders/{id}/analysisGET /traders/{id}/analysis/status
Unchanged
GET /markets/{slug}/analysis— read the latest market analysis snapshot.GET /traders/{id}/analysis— read the latest trader analysis snapshot.
Migration
Replace run-and-poll flows with direct reads. Analysis is now refreshed automatically.Before
After
Analysis responses now expose additional trader-history fields without changing route shapes or request parameters.
Added
winRateon trader-analysis responses andtopTradersentries in market-analysis responses. Based on closed positions only.latestPositionTimestampon trader-analysis responses andtopTradersentries in market-analysis responses.
null on older snapshots created before these fields were tracked.