PredictorSDK

Get market detail

Returns one market from any of the nine supported providers (Kalshi, Polymarket, Predict, SX Bet, Hyperliquid, AlphaArcade, ProphetX, Limitless, Pred).

GET
/v1/markets/{market_id}

Returns one market from any of the nine supported providers (Kalshi, Polymarket, Predict, SX Bet, Hyperliquid, AlphaArcade, ProphetX, Limitless, Pred). The market_id is either the composite form returned by GET /v1/markets ({provider}:{native_id}, e.g. kalshi:KXNBA-27-SAS) or the provider-native identifier. Composite IDs dispatch unambiguously by prefix. Native IDs are routed by format inference: Kalshi tickers match the all-caps-with-hyphens shape (KX…-…); SX Bet hashes match 0x + 64 hex characters.

A bare numeric id or kebab-case slug does not name its provider. Polymarket and Predict share both shapes, so when ?provider= is omitted the service probes every candidate and answers only if exactly one of them holds that identifier. If two do, the identifier names two different real markets and the request fails with 409 listing both — it does not pick one. Retry with ?provider= or the composite form. Polymarket also resolves a market by its conditionId, the id Polymarket wallet positions carry (polymarket:0x…, or ?provider=polymarket); a bare 0x + 64 hex id is read as an SX Bet hash. Hyperliquid integer outcome ids collide with Polymarket/Predict numeric ids and are deliberately not inferred — route them via the composite form (hyperliquid:<id>) or ?provider=hyperliquid (alias hl). AlphaArcade market ids are ULIDs (26-char Crockford base32, e.g. 01K0HQE3CEM2T2RDRWSCJ3V647); like Hyperliquid they are not inferred in v1 — route them via the composite form (alpha-arcade:<ulid>) or ?provider=alpha-arcade (alias aa). ProphetX market ids are <event_id>:<market_id> pairs (e.g. 1700008812:219 — the market id is a per-sport TYPE id repeated on every event of that sport, 219 being Moneyline on every NFL game, so the event half is the identity); like Hyperliquid they are not inferred in v1 — route them via the composite form (prophetx:1700008812:219) or ?provider=prophetx (aliases prophet-x, px). That pair resolves whichever line the venue currently flags favourite, which moves; a third part names one line, favourite or not (<event_id>:<market_id>:<line>, e.g. 1700008812:1700009030:69.5), and a line the venue no longer lists answers 404. Matched ProphetX player props use that form. Limitless market ids are kebab-case slugs (e.g. england-vs-sri-lanka-1789383376774); like Hyperliquid they are not inferred in v1 — the shape collides with Polymarket/Predict slugs — route them via the composite form (limitless:<slug>) or ?provider=limitless. Pred market ids are <parent_market_id>:<child_market_id> pairs of 0x + 64-hex ids (e.g. pred:0xaa7f…3bf5:0xaa7f…3bf5); like Hyperliquid they are not inferred in v1 — the halves collide textually with SX Bet market hashes — route them via the composite form or ?provider=pred. A bare pred:<parent> addresses the parent as a group (one outcome per child selection, marked from each child's record: its declared result once settled, otherwise no price, since no book is read); the pair addresses one binary child market, quoted from its order book while it trades and marked with its declared result once settled.

If you already know the provider, always say so. Every listing that hands you an identifier also hands you its provider, so the composite form — which GET /v1/markets returns natively in data[].id — or ?provider={row.provider} costs nothing, skips the probe, and cannot 409. It is also strictly more available: the probe has to reach both candidates to prove there is no collision, so it fails when either is having an outage, while a named provider only depends on that one.

Identity fields (id, provider, provider_id, title, status and outcomes[].name) are strict-universal: every platform's single-market endpoint exposes them natively without a second fetch. Close timestamps and parent event ids remain omitted (not nullable) — Predict's close time lives on the parent category and Polymarket's market record carries no event id.

What the pricing tier is for, and what it is not. It reports the top of each venue's book, once, at the moment of your request. That is enough to see where a market is quoted, to compare venues, and to decide where to go and look harder. It is NOT an execution feed: there is no depth beyond the best level, no streaming, no per-outcome book on the platforms that publish only a market-wide mark, and nothing here is reserved for you — by the time you act, the level may be gone. Two limits are worth knowing before you write a strategy against it. First, price is a derived display number and a non-null price does not imply a tradeable one; read pricing.availability and prefer bid/ask for anything you intend to act on. Second, quote freshness is a property of the venue, not of this API — see Bounding quote freshness below. Route the actual order through the venue's own book.

The pricing tier adds per-outcome quotes (price, bid, ask and last, as 0–1 probability numbers — price IS the implied probability), a pricing envelope (availability, scale, source, as_of, as_of_kind, observed_at and neg_risk), and market-level aggregates (liquidity_usd, volume_24h_usd, volume_total_usd, plus Kalshi contract-count mirrors and open_interest).

Where the quotes come from (pricing.source). Kalshi, Polymarket and Predict quote from the same record the identity fetch returns (pricing.source=market_record), and so do the group views of Limitless (a group's slug) and Pred (a bare pred:<parent>), which read no order book and mark each option from its own record. Every other market is priced from the venue's order book (pricing.source=orderbook). ProphetX publishes its resting offers on the market record itself, so it costs no extra request. SX Bet, Hyperliquid, AlphaArcade, a single Limitless market and a Pred child market carry no pricing on the market record, so the server makes one bounded second fetch to the book — SX Bet's /orderbook-v3/snapshot, Hyperliquid's merged l2Book, AlphaArcade's get-full-orderbook, Limitless's /markets/{slug}/orderbook, or Pred's order book for that child. AlphaArcade's is a 4-sided YES/NO book: the second side's quotes are derived from the first by the cross-side complement, and the catalog midpoint serves as the price mark when the book is empty — reported as pricing.availability=indicative, since a mark that outlives its book is not a quote. Limitless and Pred publish the YES side only, and the NO side is its complement. Pricing failures never fail the lookup: if the book read fails, identity stays intact, SX Bet and Hyperliquid (whose only prices are in the book) degrade to pricing.availability=unavailable, and AlphaArcade, Limitless and Pred keep the record's marks, which pricing.availability then reflects.

Predict publishes a per-market spreadThreshold — the widest bid/ask spread it counts as liquidity — and this route honours it, so a Predict book outside its own market's threshold reports indicative rather than lending its midpoint the authority of live. Aggregates a platform doesn't natively expose are explicit null (e.g. Kalshi reports volume in contracts, so volume_*_usd stays null rather than fabricating a USD figure; its upstream liquidity_dollars field is deprecated and always zero, so liquidity_usd is null too).

Bounding quote freshness. pricing.as_of is the provider's own timestamp and does not mean the same thing on every platform — on Hyperliquid it moves with the order book, while on Kalshi it is a record write measured anywhere from 15 hours to 137 days old on markets reporting status: open with a live two-sided book. pricing.as_of_kind names which one you received (quote / record_refresh / record_static / unknown), so read it before applying an age bound to as_of; only quote tracks the quote closely enough to bound at all. pricing.observed_at is when this server read the quotes, means the same thing on every provider, and is therefore the field to bound when you need one threshold that behaves identically across platforms. It bounds the age of the read, not of the quote: this route reads the venue live per request and caches nothing, so on a record_static provider a fresh observed_at beside a day-old as_of is the honest description of what the venue served, and the executable price should come from that venue's own book.

The trading_fees tier reports what the VENUE charges to trade this market — its own published fee parameters, normalized to one shape across all nine platforms, so cross-venue cost comparison stops requiring nine private formulas. Nothing here relates to PredictorSDK's subscription pricing. It is always present, and trading_fees.availability distinguishes published parameters from per-account rates that need your own venue credentials (SX Bet, Hyperliquid), from a venue that publishes nothing, and from a fee of genuinely zero. Only Kalshi costs extra upstream hops for it (its parameters live on the parent series plus any scheduled per-event override, all TTL-cached and bounded); those degrade to availability: "unavailable" rather than failing the lookup, exactly like the pricing tier. See the MarketDetailTradingFees schema for the formulas and for what is deliberately out of scope.

Authorization

BearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

market_id*string

Composite ({provider}:{native_id}) or provider-native market identifier. Examples per provider: Kalshi market ticker (KXNBA-27-SAS), Polymarket numeric id or slug (540817 or nfl-pit-ne-2026-09-20), Predict market id (356635), SX Bet marketHash (0x…64hex), Hyperliquid outcome id (use the composite hyperliquid:<outcome-id> or ?provider=hyperliquid — bare integer ids aren't inferred).

A bare numeric id or slug is not unique across providers. Polymarket and Predict both use these shapes and their id spaces overlap, so sending one without a provider can fail with 409 (see that response). Prefer the composite form — it is what GET /v1/markets returns in data[].id — or pass ?provider=.

Sports identifiers expire. Kalshi game tickers and Polymarket game slugs are delisted as events settle, and a Hyperliquid outcome id lives as long as its question: its daily-recurring price outcomes roll over every day, while a season-long question (a league winner, say) stays listed until it resolves. Take current ids from GET /v1/markets or GET /v1/matching-markets/sports rather than copying one out of this reference. Long-dated markets (Kalshi season futures, multi-year AlphaArcade questions) and settled Polymarket, Predict and SX Bet ids stay resolvable.

Query Parameters

provider?string

Optional provider override, spelled like the provider field on GET /v1/markets rows and every other response (it was platform until 2026-10-09; ?platform= now answers 400 naming this parameter). When omitted, inferred from the composite prefix or from the native ID format (KX… → Kalshi, 0x…64hex → SX Bet — Pred ids share that shape and are never inferred; use pred:… or ?provider=pred). Numeric IDs and kebab-case slugs are shared shape between Polymarket and Predict; in that case the service probes both and returns 409 rather than guessing if the identifier resolves on both. Hyperliquid integer ids collide with these numerics and are not inferred — use the composite hyperliquid:<id> or ?provider=hyperliquid (alias hl). AlphaArcade ULIDs and Limitless slugs are not inferred either — use the composite form (alpha-arcade:<ulid>, limitless:<slug>) or the matching ?provider= value. Pred pairs (pred:<parent>:<child>) are likewise composite/?provider= only. Passing provider explicitly skips the probe entirely and is the recommended call whenever you know it. When the override contradicts a composite prefix (e.g. kalshi:X with ?provider=polymarket), the request returns 400.

Value in

  • "kalshi"
  • "polymarket"
  • "predict"
  • "sxbet"
  • "hyperliquid"
  • "alpha-arcade"
  • "prophetx"
  • "limitless"
  • "pred"

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/markets/kalshi:KXNBA-27-SAS"

{  "id": "kalshi:KXNBA-27-SAS",  "provider": "kalshi",  "provider_id": "KXNBA-27-SAS",  "title": "Will San Antonio win the 2027 Pro Basketball Finals?",  "status": "open",  "outcomes": [    {      "name": "Yes",      "outcome_id": "yes",      "price": 0.235,      "bid": 0.23,      "ask": 0.24,      "last": 0.23,      "bid_size": 21414.84,      "ask_size": 133432.35    },    {      "name": "No",      "outcome_id": "no",      "price": 0.765,      "bid": 0.76,      "ask": 0.77,      "last": 0.77    }  ],  "pricing": {    "availability": "live",    "scale": "probability_0_1",    "source": "market_record",    "as_of": "2026-07-24T16:41:17.536752Z",    "as_of_kind": "record_static",    "observed_at": "2026-08-21T03:41:07.000Z"  },  "trading_fees": {    "availability": "published",    "observed_at": "2026-08-21T03:41:07.000Z",    "source": "series_record",    "charge_basis": "fill",    "taker": {      "model": "quadratic",      "rate": 0.07,      "exponent": 1,      "rounding": {        "direction": "up",        "increment": 0.0001      }    },    "maker": {      "model": "quadratic",      "rate": 0.0175,      "exponent": 1,      "rounding": {        "direction": "up",        "increment": 0.0001      }    }  },  "liquidity_usd": null,  "volume_24h_usd": null,  "volume_total_usd": null,  "volume_24h_contracts": 1049.81,  "volume_total_contracts": 629558.2,  "open_interest": 436690.85}