↑ ↓ move · Enter open · Esc close

Get started / Changelog

API Changelog

Every change to the public API contract - new endpoints, parameters, response shapes, and deprecations - recorded by date. The raw source is available at /api-changelog.md.

2026-09-27

  • Explicit Kalshi ticker subscriptions on WebSocket prices now share the dedicated Kalshi feed while retaining price_update messages and numeric cent prices. Existing snapshots, entitlements and subscription limits remain. Kalshi readiness and interruption warnings identify when REST price reconciliation is required. Group-only subscriptions retain the general price feed.

2026-09-25 · v8.1.1

  • /markets now returns a structured 400 for limits outside 1-2000 or malformed integers.
  • /search matches short uppercase acronyms such as NFL as whole words, so unrelated words such as inflation no longer match.
  • WebSocket price and orderbook examples now consistently show prices in cents.

2026-09-25 · v8.1.0

  • Corrected EV gain per dollar to equal ROI divided by 100, with binary payout checks.
  • Added top-holder offset pagination and explicit top-20-per-outcome coverage metadata.
  • Added volume materialization watermark, refresh time and lag metadata.
  • Reject malformed trade time bounds with a structured 400 response.
  • Hydrate native Kalshi tickers from captured current quotes in bulk prices.
  • Withhold confirmed election office/year contradictions from matched discovery and opportunities; unified books return 409 for conflicting groups and populate event/outcome labels.
  • Unknown WebSocket channels now return the documented UNKNOWN_CHANNEL code.

2026-09-25

Changed in OpenAPI 8.0.0

  • /status now reports broad market availability. It reports ok when a strict majority of venues have live markets, and degraded when that majority is lost. Individual venue status no longer labels a venue stale solely because a full catalog refresh is late. last_updated now shows the latest observed matched-market price update or successful catalog refresh, whichever is newer. It does not imply that every market has a current quote.

2026-09-24

Changed in OpenAPI 7.0.0

  • Polymarket token volume and volume chart now default to the last 24 hours when start_ts is omitted. This keeps the default hourly query bounded. Pass start_ts to request longer history within the existing bucket limits.
  • /status now reads recorded completed catalog syncs for venue connectors and uses the catalog watchdog's venue-specific freshness thresholds. Legacy refresh attempts no longer override those venues' catalog status.

Added

  • Kalshi-specific kalshi_prices WebSocket channel with decimal-dollar ticker updates, explicit recovery signals, and Enterprise all-market subscriptions, including combinations and short-duration markets. Existing price entitlements apply.
  • Native creation, metadata-update, and settlement time windows on /api/v2/kalshi/markets for symbol reconciliation. Existing created_since observation-time behavior remains unchanged.

2026-09-23

Corrected in OpenAPI 6.6.0

  • /status reads Opinion's latest complete catalog sync instead of its retired refresh log. Missing or incomplete syncs cannot advance its freshness.

  • /trades documents a moving retention window instead of a fixed May 19 start. Read _meta.data_available_from from a live response before planning backfills. The default remains the last 48 hours for unfiltered requests, or the full served range for market, token, and wallet filters.

  • Smart Activity documents _meta.warming for every window. A warming response has no available ranking; its empty list does not mean no activity. Retry with backoff and treat persistent warming as unavailable.

  • Polymarket token and condition volume responses may be reused for up to 20 seconds to reduce repeated database work.

Corrected in OpenAPI 6.5.0

  • /events documents its accepted status filters (active and all) and the existing include_groups=true default. Responses may still report status: completed for past events.
  • /kalshi/markets documents volume_fp and open_interest_fp as fixed-point strings, matching the current catalog response. Legacy integer volume and open_interest remain optional when supplied by Kalshi. Generated clients should refresh their types for these fields.
  • The WebSocket prices reference now gives bid, ask, and last price units in cents (0 to 100). The URL matcher reference lists only the four accepted URL hosts: Polymarket, Kalshi, PredictIt, and Novig.

Added

  • OpenAPI 6.4.0 adds include_prices to /search (default true). Set include_prices=false to omit last_price, yes_bid and yes_ask and skip the price lookup for faster searches. Values other than true/false (or 1/0, yes/no) return 400.
  • OpenAPI 6.1.0 documents the X-Request-ID response header. Send a UUID in X-Request-ID to correlate your request, including client-side timeouts, with support diagnostics. Other values are replaced with a server-generated UUID. Server completion does not confirm that your client received the body.
  • Added REST reference pages and interactive examples for /alerts/smart-money and /alerts/fade-finder, including filters, pagination, signal types, and plan quotas.

Changed

  • OpenAPI 6.4.0: /search prices now come from current order books. last_price is the midpoint of the current best YES bid and ask, in cents, rather than the last recorded price. It is null when either side is missing or the spread is wider than 20 cents. Markets in completed events or settled groups, and markets without a current quote, return null prices, and every market now carries all three price keys. If current prices cannot be read, every price is null and _meta.prices_unavailable is true; retry later.
  • OpenAPI 6.3.0: /kalshi/markets delta mode (created_since) now examines at most limit newly observed markets per page for every status, so a page filtered by status or category can hold fewer markets than limit, or none, while cursor is non-null. Keep paging until cursor is null: a complete walk returns the same markets as before. This fixes status-filtered delta requests on wider windows that could exceed the server time limit and return HTTP 500. Under status=open, markets we already know have closed are still skipped and are not listed in omitted_tickers.

Fixed

  • OpenAPI 6.2.0 documents the existing nullable /markets total_count and its as_of response timestamp. Response behavior is unchanged.

  • Corrected the remaining /arb and /ev parameter prose to match their existing min_roi=0.0 default. Opportunity selection is unchanged.

2026-09-22

Changed

  • OpenAPI 6.0.0: /status reports degraded when any catalog refresh is unhealthy. If health cannot be determined, it returns HTTP 503 with status: "unknown". Handle these states in monitoring. Refresh timestamps describe catalog refresh attempts, not live quote freshness.
  • /search accepts status=active|completed|all. Unsupported values now return HTTP 400 instead of silently selecting active events. The previously advertised resolved and cancelled values were not supported. completed includes events outside their visibility window and does not imply settlement.

Fixed

  • OpenAPI 6.0.1 corrects /search to document its existing include_groups=true default. Set include_groups=false to retrieve event summaries and group counts without expanded markets and prices. The runtime default is unchanged.

  • Corrected /arb and /ev documentation to show the existing min_roi=0.0 default. Default opportunity results are unchanged.

  • Documented the live_games WebSocket channel, event_ids scope, and UNKNOWN_EVENT_ID warning. Trade messages are scoped to live games; there is no standalone trades channel.

  • Invalid WebSocket URL credentials retain their authentication failure reason instead of being replaced by a message-authentication timeout.

2026-09-17

Changed

  • Novig market URLs (market_url_novig, url on Novig legs and cells) are now Novig's mobile-aware links (novig.onelink.me/...): they open the Novig app on the order slip when it is installed, the app store otherwise, and the novig.com order slip on desktop. GET /v2/matching-markets/url resolves both this form and the previous novig.com/events/... form. OpenAPI 5.2.1.

2026-09-15

Added

  • GET /v2/matching-markets/url resolves Novig deep links (novig.com/events/<outcome_id>/<partner_id>?referralCode=...): the outcome id in the path identifies the market, so a link copied from a Novig order slip now returns its matched group. OpenAPI 5.2.0.

2026-09-14

Changed

  • Prediction.com is now the recommended API origin. New integrations should use https://prediction.com/api/v2 and wss://ws.prediction.com. Existing integrations may continue using https://www.predictionhunt.com/api/v2 and wss://ws.predictionhunt.com; both compatibility endpoints remain supported and API requests are served directly rather than redirected.
  • OpenAPI 5.1.1 lists the new recommended production endpoint first while retaining the old production endpoint and a relative local/preview endpoint.

2026-09-11

Added

  • New platform: Novig (novig), the CFTC-regulated peer-to-peer sports exchange. OpenAPI 5.1.0 adds the enum value everywhere a platform is accepted or returned:

    • GET /v2/markets and GET /v2/prices/history: filter with platform=novig. Market ids are prefixed (novig_<outcome_id>); each Novig outcome is its own market and the venue market id is returned in ticker_name.
    • GET /v2/orderbook: platform=novig. Books are available for markets matched to a cross-platform event and refresh on the polling cadence; the long (Yes) side is quoted and the short side is priced as its complement, so no levels are empty (same as polymarket_us and predictfun).
    • GET /v2/arb and GET /v2/ev: platforms=novig filters to opportunities whose legs include the venue; ArbLeg and EVLeg gain novig. Fee-adjusted ROI uses the venue's schedule: no taker fee before the game starts, 0.03 x P x (1 - P) per contract once it is live, and 0.06 x P x (1 - P) on NFL and NCAAF futures.
    • GET /v2/status: a novig entry in platforms.
    • WebSocket prices, arb and ev channels: ticks and legs with source: "novig".

    Novig is not covered by GET /v2/trades or the smart-money feeds (no public attributed trade or wallet data) and cannot be resolved by GET /v2/matching-markets/url yet (Novig links address a bet slip, not a market page).

2026-09-07

Fixed

  • OpenAPI 5.0.0 corrects the existing GET /v2/markets contract. The accepted status filters are active, closed, and all (default active). The previously advertised resolved and cancelled filters are rejected by the API; use closed to retrieve closed markets. Regenerate clients that derive status enums from the spec. This major spec version corrects the published enum; endpoint behavior has not changed.
  • Document the existing 2,000-row page limit and optional include=rules response section, including the optional rules object and validation errors.

2026-08-21

Changed

  • Price History documentation now uses consistent, platform-neutral positioning: Historical OHLC price data normalized by Prediction Hunt across supported markets.

2026-08-20

Fixed

  • Kalshi path parameters in the interactive docs are now substituted into the URL. The Market playground previously generated a request to the literal path /kalshi/markets/{ticker} and also appended ?ticker=…, which always returned not_found.resource. It now generates and executes /kalshi/markets/<full-market-ticker> as documented. This fix applies to all interactive endpoint pages with path parameters.

  • GET /v2/prices/history now covers Kalshi tickers discovered through the full catalog. Prediction Hunt now delivers normalized Kalshi candlestick coverage for active, settled, and archived contracts on the existing 0-100 scale. Use the catalog's full market-level ticker, not event_ticker. The endpoint accepts 1m, 5m, 15m, 1h, and 1d; Prediction Hunt builds Kalshi 5m/15m candles from one-minute price history.

  • GET /v2/kalshi/markets/{ticker} now follows Kalshi's archive boundary. Rules, timing, result, and settlement fields remain available after a settled market moves into archival availability.

2026-08-13 (later)

Added

  • _meta.degraded on GET /v2/kalshi/markets delta responses. Present and true only while delta serving is temporarily degraded. During such periods the returned watermark is frozen at your created_since rather than advancing, so newly observed markets are never skipped past while degraded: keep polling with the same value and the window re-opens automatically on recovery. You may receive repeated markets across those polls; deduplicating on ticker, which the polling contract already requires, handles them. The field is absent in normal operation, so existing integrations need no change.

2026-08-13

Fixed

  • GET /v2/kalshi/markets?created_since=… now sees short-lived markets. Delta mode resolved its window from our catalog sync, which enumerates open markets every 30 minutes. A market whose entire open window fell between two syncs was never observed, so it could never appear in a delta response. This affected Kalshi's short-dated books in particular, including the 15-minute crypto series (KXBTC15M, KXETH15M, KXSOL15M and siblings), where roughly a third of markets were reaching delta callers.

    Delta mode now resolves its window from a first-seen ledger fed by our whole-venue quote capture as well as the catalog sync, so a market becomes eligible on the first quote we receive for it rather than on the next catalog sweep.

    No request changes are required. Responses gain no new fields and lose none.

Changed

  • first_seen_at is documented as our observation time. It has always been the instant our capture first saw a market, never a venue-stated listing or open time, and the docs now say so. It may also be revised earlier if a source that saw the market sooner reports it later. Pagination is unaffected: the cursor pages on a separate immutable ordering key, so a revised first_seen_at cannot move a market behind a watermark you have already passed.

  • _meta.omitted_tickers is the place to look for short-lived markets. Its meaning is unchanged, but the docs now call out the case that matters: a market that opens and closes between two of your polls is past its close time by the time you ask, so under a status filter that excludes finished markets (for example status=open) it does not arrive in markets. When we do not yet hold a close time for it, it is reported in omitted_tickers; when we already knew it had closed, it is skipped before that list is built so wide windows stay pageable. So the list is worth reading, but it is not an exhaustive record of everything listed in the window. Poll at least as often as the shortest-lived book you care about.

  • created_since filters on an internal record time, not on first_seen_at. These are deliberately different values, and the distinction is what keeps a late-arriving observation from being skipped forever. A market whose first_seen_at predates your created_since can legitimately appear in the window: that happens when a source that saw the market earlier reports it late, and the earlier timestamp is the more accurate one. Treat first_seen_at as information rather than as a bound to re-check, and do not discard such a market as out-of-window.

    Existing cursors keep working across this change. A pagination cursor issued before the switch continues to page the previous backend until that walk finishes, so a walk already in flight is never re-ordered mid-way.

2026-08-11

Changed

  • GET /v2/kalshi/markets now excludes Kalshi's auto-generated combo (parlay) markets by default. These multi-leg series are roughly 99% of the raw venue feed, which meant a status=open crawl paged through more than 700,000 markets to reach the roughly 83,000 standalone markets most integrations actually want. The default is now the filtered view: the same crawl is about 83 pages instead of 700.

    This changes the default response set, so re-check any code that assumed the combo series were present.

    Set include_combos=true to restore the previous behavior. The value must be true or false; anything else returns a 400 rather than silently falling back to the default, because the flag changes the result set by an order of magnitude.

    include_combos=true is not valid alongside created_since and returns a 400 there: combo markets have never been tracked in the delta catalog, so delta responses were already combo-free and are unaffected by this change.

Fixed

  • GET /v2/kalshi/markets now rejects a comma-separated status with a clean 400 instead of surfacing an upstream error as a 502. The status parameter takes a single value: one of unopened, open, closed, settled. Earlier docs describing a comma-separated subset were wrong: the upstream venue has never accepted one, so no working integration is affected by this change.
  • Documented Kalshi's response-side status vocabulary. Market objects returned by this endpoint carry Kalshi's own lifecycle values (initialized, active, closed, determined, finalized), which differ from the request filter's vocabulary. In particular, markets matching status=open read "active" in the response, so do not re-filter the response body on the literal "open".

2026-08-06

Added

  • GET /v2/kalshi/markets gains a delta mode for keeping a mirrored catalog current without re-crawling it. Pass created_since (Unix seconds or ISO 8601) to receive only markets first listed after that instant, oldest first, with live prices and status as usual. Each market carries first_seen_at, and _meta adds:

    • watermark: pass this back as the next created_since. It is computed with a safety margin, so a few markets may repeat across polls; deduplicate on ticker. Do not substitute your own clock.
    • omitted_tickers: tickers first listed inside the window that the response does not include (filtered out by status or category, or momentarily unavailable), so a delta consumer never silently loses a ticker.

    status, category, and limit combine with created_since; page with cursor until it is null. tickers, event_ticker, series_ticker, min_close_ts, and max_close_ts are rejected alongside it, since their regular meaning does not survive inside a created-since window.

    When status excludes finished markets (for example status=open), a created_since walk skips markets already past their close time. Most of what a venue has ever listed is over, so this is what lets a wide window reach currently open markets on the first page rather than paging through the entire history.

2026-07-30

Changed

  • Polymarket US (polymarket_us) is now documented everywhere it is accepted. No behavior change — the venue was already live on these surfaces, but the spec and docs pages did not list it:

    • GET /v2/orderbook — platform=polymarket_us is supported. As on predictfun, only the long (Yes) side is quoted and the short side is priced as its complement, so no levels come back empty.
    • GET /v2/arb and GET /v2/ev — platforms=polymarket_us filters to opportunities whose legs include the venue (ArbLeg and EVLeg already carried the enum value).
    • MarketPrice and OrderbookLevel — Polymarket US quotes use the same 0-100 cents scale as every other platform.

    Polymarket US is still not covered by GET /v2/trades or the smart-money / fade-finder feeds (custodial venue, no public attributed trade or wallet data), and cannot be resolved by GET /v2/matching-markets/url (the venue publishes no web market pages for a URL to point at).

2026-07-16

Added

  • Arbitrage and +EV opportunity responses can now include Polymarket US legs: the platform enum on ArbLeg and EVLeg gains polymarket_us. Polymarket US market ids are prefixed (polymarket_us_<id>), quotes come from the venue's public gateway, and fee-adjusted ROI uses the venue's taker fee curve (0.06 × P × (1−P) per contract by default). Handle the new enum value when parsing /v2/arbitrage/opportunities and /v2/ev/opportunities responses.

2026-07-15

Added

  • GET /v2/trades coverage errors (opt-in). A new HTTP 422 response code history_outside_hot_window is being introduced behind a feature flag. When enabled, a request whose start_time (or a paginated cursor's bound coverage window) starts before the earliest available data returns 422 with a structured data_available_from field and a pointer to the historical data product, instead of silently clamping the range up to the coverage start. The data_available_from value documents current coverage (2026-05-19T00:00:00Z) and is surfaced in _meta.data_available_from on in-range responses. Pagination cursors bind to the coverage window at mint time: a cursor keeps working while coverage is unchanged, and returns the same 422 (never a silently shrunk page) if coverage later moves past it. While the flag is disabled the endpoint behaves exactly as before — an out-of-window start_time is clamped up to data_available_from. No action is required today; if you page /v2/trades, keep following the returned pagination_key and read _meta.data_available_from to know the coverage start.

2026-07-14

Added

  • New endpoint: GET /v2/kalshi/series — list Kalshi series for a category (required category, case-insensitive, same values as the /v2/kalshi/markets filter), with ticker, title, tags, and frequency. Fetch the list once, then pull each series' markets from GET /v2/kalshi/markets?series_ticker=<ticker>; requests are independent and can run in parallel.
  • WebSocket prices channel — subscriptions now cover the entire live Kalshi catalog, not just markets tracked on Prediction Hunt. Subscribing with any valid Kalshi market ticker (e.g. one discovered via GET /v2/kalshi/markets) returns an immediate price snapshot and begins streaming live ticks within a few seconds; only tickers Kalshi itself does not recognize return UNKNOWN_ID. Subscribe with the market ticker (the ticker field, e.g. KXODIMATCH-26JUL160800INDENG-IND), not the event ticker — an event ticker is not a tradeable market and still returns UNKNOWN_ID.
  • GET /v2/kalshi/markets — new category filter (e.g. ?category=sports). Kalshi's own market objects carry no category (classification lives on the series), so the filter resolves each market's series against the Kalshi series catalog server-side. Matching is case-insensitive; invalid values return a 400 listing the accepted categories. A filtered request scans up to 10 full-size catalog pages to fill the response toward limit matching markets (_meta.pages_scanned reports the number consumed), and the cursor resumes from the last scanned page — so a response may hold fewer or more than limit markets while cursor is non-null; keep walking until cursor is null. Under category, treat limit as the target number of matching markets per response, not a hard page size.
  • GET /v2/kalshi/markets — new min_close_ts / max_close_ts filters (Unix seconds): return only markets closing inside the given window. Useful for scoping a sync to markets closing soon instead of walking the entire catalog. Combine freely with status, category, and the other filters.
  • GET /v2/kalshi/markets and GET /v2/kalshi/markets/{ticker} — every returned market is now annotated with its series-level category (e.g. Sports) and tags (e.g. Tennis), so responses are self-describing without a separate series lookup. Markets whose series is not in the Kalshi series catalog are passed through without these fields (and are excluded when a category filter is active). If Kalshi ever adds these fields to market objects natively, the upstream values win.

2026-07-13

Added

  • New platform: Polymarket US (polymarket_us) — the CFTC-regulated US exchange, a separate venue from international Polymarket (polymarket) with its own markets, ids, and pricing. Now available on:

    • GET /v2/markets and GET /v2/prices/history — filter with platform=polymarket_us. Market ids are prefixed (polymarket_us_{id}); the platform slug is returned in ticker_name.
    • GET /v2/orderbook — platform=polymarket_us. Books are available for markets matched to a cross-platform event and refresh on the polling cadence; the long (Yes) side is quoted and the short side is priced as its complement, so no levels are empty (same as predictfun).
    • GET /v2/status — a polymarket_us entry in platforms.
    • WebSocket prices channel — subscribed markets include polymarket_us ticks with source: "polymarket_us".
    • /api/odds/grid and /api/odds/event_rows — a polymarket_us cell per row alongside the existing platforms.

    Not included (yet): GET /v2/trades (Polymarket US exposes no public attributed trade feed), smart-money/fade-finder channels (custodial venue, no wallet data), and arbitrage/EV signals (rolling out separately).

2026-07-09

Changed

  • GET /v2/markets — the q filter now also matches series_title (the event/game phrasing), so a market whose title is a bare outcome label (e.g. a Kalshi player prop Bobby Witt Jr.: 1+) is findable by the event wording like home runs. The existing title and market_id matching is unchanged, so this only widens what q finds.
  • GET /v2/markets — ProphetX market title is now the clean outcome label (e.g. Total over 9.5, New York Mets spread plus 3.5) instead of the internal MLB-2026-07-09-… key. event_title (the game) is unchanged, and other platforms are unaffected.
  • Sports group titles across GET /v2/events, GET /v2/search, and GET /v2/matching-markets/sports no longer carry a leading YYYY-MM-DD (e.g. 2026-07-09 Philadelphia Phillies → Philadelphia Phillies). The date is available in each game's event_date.
  • GET /v2/matching-markets/sports now returns only game moneylines by default. Sports events increasingly carry spreads, totals, and player-prop groups alongside the moneyline; previously this endpoint returned all of them intermixed, so a single game surfaced dozens of games[] entries with no way to tell a moneyline from an over/under. It now defaults to the moneylines (the game winners). This is a breaking change for integrations that relied on spreads/totals/props appearing by default — pass the new types parameter to get them back: ?types=all restores the previous behavior, or request specific classes, e.g. ?types=moneyline,spread,total,player_prop.
  • WebSocket subscribe / unsubscribe — market_ids now also accept the REST-style platform:market_id composite form used by GET /v2/prices/bulk (e.g. kalshi:KXMENWORLDCUP-26-FR), on every market-keyed channel (prices, orderbook). The server strips the platform prefix; the subscribed confirmation and all streamed messages continue to carry the platform-native market_id (e.g. KXMENWORLDCUP-26-FR) plus a separate source field. Previously the composite form triggered an UNKNOWN_ID warning and delivered no data. Bare platform-native ids keep working unchanged.

Added

  • Market-type classification on every matched group. Group objects on GET /v2/matching-markets/sports, GET /v2/events, GET /v2/search, and GET /v2/matching-markets now include:
    • market_class — a small, stable enum to switch on: moneyline, spread, total, player_prop, other (null on non-sports groups). Filter on this, not on titles. Esports lines fold into the same classes as traditional sports — a map handicap is a spread and a total-maps line is a total (so ?types=spread/?types=total work across every sport) — while per-map winners and game-stat props (first blood / kills) are other.
    • market_type — the specific type (e.g. spread, 1h_total, player_home_runs, method_of_victory). Open-ended; new values appear without notice, so branch on market_class.
    • period (full/1H), line, side (home/away/over/under), player (player props), and team (team lines) — null where not applicable.
  • types filter on GET /v2/events and GET /v2/search. Comma-separated market_class values (or all) restrict each event's groups[] to those classes. Default is unchanged (all classes).
  • event_id and event_name on GET /v2/matching-markets/sports games. Every group for one game now shares an event_id, so you can group the moneyline, spreads, totals, and props back into a single game — and pair an over/under on (event_id, line). Previously the only per-group label was game_title, which collided across games (e.g. eleven different games all titled Over 9.5).

Fixed

  • GET /v2/matching-markets no longer returns events that have no cross-platform group (they previously appeared with an empty groups: []).

2026-07-03

Changed

  • GET /v2/orderbook — prices are now normalized to the same 0-100 cents scale used everywhere else in the v2 API (/v2/markets, /v2/search, /v2/prices/bulk, /v2/unified-orderbook). Previously Kalshi, Polymarket, and Opinion orderbook prices were returned on a 0-1 scale while Predict.fun was already 0-100, making the endpoint internally inconsistent and inconsistent with the rest of the surface. This is a breaking numeric-scale change for existing integrations that read yes/no bid/ask prices from /v2/orderbook — multiply old values by 100 to get the new ones (e.g. 0.62 is now 62). size fields are unaffected.
  • Corrected the MarketPrice and OrderbookLevel schema descriptions, which previously stated Polymarket prices use a 0-1 scale and that orderbook prices were "the same scale as MarketPrice" (they were not, by 100x). All price fields across every platform and endpoint are 0-100 cents.

Added

  • GET /v2/status — each platform entry now includes live_markets, the number of markets that are active and not past expiration (what /v2/markets?platform=<platform>&status=active actually returns). The existing active_markets counts every market ever ingested for the platform regardless of status, so it can be much larger; live_markets is the currently-tradeable count.
  • GET /v2/kalshi/markets/{ticker} — documented the result and settlement_value_dollars fields returned once a market settles (status becomes "finalized").

Fixed

  • GET /v2/prices/bulk (and /v2/markets, /v2/search) — a request for two or more ids at once could return prices up to a day stale for some markets; single-id requests were always fresh. The batch latest-price lookup was hitting a bad database query plan. Batched requests now return the same current prices as single-id requests — the "one id per request" workaround is no longer needed.
  • GET /v2/prices/history — volume is now the per-bucket amount traded in each candle (previously it summed a cumulative counter, producing inflated, non-comparable magnitudes), and mid no longer collapses to 50 after a market settles (it falls back to close when the book is empty). See the updated volume/mid field docs.
  • Polymarket last_price on /v2/markets and /v2/search — for markets whose outcomes are ordered [No, Yes], last_price was being reported as the NO-side price (outside the [yes_bid, yes_ask] band). It is now always the YES-side price. yes_bid/yes_ask were already correct.
  • GET /v2/events — no longer returns auth.endpoint_blocked for keys whose plan blocks /v2/ev; an internal prefix match was incorrectly catching /v2/events. The endpoint is available on all plans that were meant to have it.

2026-07-02

Fixed

  • Price/size fields (yes_bid, yes_ask, no_bid, no_ask, last_price, volume, liquidity) across GET /v2/markets, GET /v2/prices/bulk, GET /v2/events/search, and the sports-matching endpoints now serialize a stored 0 as 0 instead of null. Only a genuinely missing value is null.

Added

  • GET /v2/prices/bulk now returns _meta alongside prices: {requested, resolved, unresolved_ids}. Previously an id that could not be resolved (malformed pair, or no recent price data) was silently dropped from the response with no way to distinguish it from an id that was never requested. prices is unchanged and remains backward compatible.

Changed

  • GET /v2/markets — the q filter now also matches market_id, in addition to title. Per-market tickers/ids (e.g. a Kalshi KXMLBGAME-* moneyline) are findable by q even when the market's title is a generic team/outcome label. No request or response shape change.

2026-06-29

Changed

  • GET /v2/trades — an unfiltered request with no start_time now defaults to a recent window (last 48h) instead of the full served range, so the broad feed stays fast. Requests that pass a market_id, token_id, or wallet filter still default to the full history. The applied window is echoed in _meta.start_time / _meta.end_time, and _meta.default_window_applied is true when the recent-window default was used. To read deeper history on the unfiltered feed, pass an explicit start_time.

2026-06-23

Added

  • GET /v2/kalshi/markets — the full Kalshi market catalog with live prices and status, paginated by cursor. Filter by status, event_ticker, series_ticker, or specific tickers. Walk cursor until it is null to mirror every Kalshi market.
  • GET /v2/kalshi/markets/{ticker} — a single Kalshi market by ticker, with live prices, status, and resolution rules.

2026-06-18

Added

  • Published this API changelog. Every change to the public API contract is now recorded here with a date and a summary of what changed.