@mostlyrightmd/markets/market-data
Classes
Section titled “Classes”MarketContractError
Section titled “MarketContractError”A caller-supplied value violates a market-data contract, caught before I/O.
The market-data twin of Python’s pre-I/O ContractError usage: an
unparseable market reference, an unfiltered listing sweep, an outcome the
market does not offer. Carries the teaching fields (field / expected /
actual / location) so the caller gets the fix, not just a refusal.
Extends
Section titled “Extends”MarketDataError
Constructors
Section titled “Constructors”new MarketContractError()
Section titled “new MarketContractError()”new MarketContractError(
message,options):MarketContractError
Parameters
Section titled “Parameters”message
Section titled “message”string = ""
options
Section titled “options”ContractErrorOptions = {}
Returns
Section titled “Returns”Overrides
Section titled “Overrides”MarketDataError.constructor
Properties
Section titled “Properties”
readonlycode:string
Stable string enum for branching without parsing message text.
Inherited from
Section titled “Inherited from”MarketDataError.code
defaultErrorCode
Section titled “defaultErrorCode”
staticdefaultErrorCode:string="CONTRACT_ERROR"
Overrides
Section titled “Overrides”MarketDataError.defaultErrorCode
UnsupportedResolutionError
Section titled “UnsupportedResolutionError”An interval value is outside the venue’s supported resolution set.
The price-history verbs take interval: "1m" | "1h" | "1d". A value the
venue does not serve is a fixable typo, so the error hands back the fix: the
message names the whole valid set and supported carries it structurally, so
a caller (or an agent) can branch without parsing prose.
try { await candles(ticker, { interval: "5m", ... });} catch (err) { if (err instanceof UnsupportedResolutionError) { console.log(err.venue, err.interval, err.supported); }}Extends
Section titled “Extends”MarketDataError
Constructors
Section titled “Constructors”new UnsupportedResolutionError()
Section titled “new UnsupportedResolutionError()”new UnsupportedResolutionError(
message,options):UnsupportedResolutionError
Parameters
Section titled “Parameters”message
Section titled “message”string = ""
options
Section titled “options”UnsupportedResolutionErrorOptions = {}
Returns
Section titled “Returns”Overrides
Section titled “Overrides”MarketDataError.constructor
Properties
Section titled “Properties”
readonlycode:string
Stable string enum for branching without parsing message text.
Inherited from
Section titled “Inherited from”MarketDataError.code
defaultErrorCode
Section titled “defaultErrorCode”
staticdefaultErrorCode:string="UNSUPPORTED_RESOLUTION"
Overrides
Section titled “Overrides”MarketDataError.defaultErrorCode
interval
Section titled “interval”
readonlyinterval:null|string
supported
Section titled “supported”
readonlysupported:null| readonlystring[]
Normalised to string[] so the payload is JSON-stable whatever iterable arrived.
readonlyvenue:null|string
VenueCapabilityError
Section titled “VenueCapabilityError”A verb exists in the shared venue grammar but this venue has no such concept.
The market-data verbs speak one grammar across venues, but the venues’ own
hierarchies differ: Kalshi is Series -> Event -> Market, Polymarket is
Event -> Market with no series tier at all. So polymarket.series() exists
(the grammar is shared) and raises this rather than returning an empty
result, which would read as “no series right now” instead of “never any”.
remedy names the verb to call instead.
Extends
Section titled “Extends”MarketDataError
Constructors
Section titled “Constructors”new VenueCapabilityError()
Section titled “new VenueCapabilityError()”new VenueCapabilityError(
message,options):VenueCapabilityError
Parameters
Section titled “Parameters”message
Section titled “message”string = ""
options
Section titled “options”VenueCapabilityErrorOptions = {}
Returns
Section titled “Returns”Overrides
Section titled “Overrides”MarketDataError.constructor
Properties
Section titled “Properties”capability
Section titled “capability”
readonlycapability:null|string
readonlycode:string
Stable string enum for branching without parsing message text.
Inherited from
Section titled “Inherited from”MarketDataError.code
defaultErrorCode
Section titled “defaultErrorCode”
staticdefaultErrorCode:string="VENUE_CAPABILITY"
Overrides
Section titled “Overrides”MarketDataError.defaultErrorCode
remedy
Section titled “remedy”
readonlyremedy:null|string
readonlyvenue:null|string
Interfaces
Section titled “Interfaces”BookOptions
Section titled “BookOptions”Properties
Section titled “Properties”capturedAt
Section titled “capturedAt”
readonlycapturedAt:Date
Client-clock snapshot instant, used when the venue stamps none.
marketId
Section titled “marketId”
readonlymarketId:string
FetchClobPricesHistoryArgs
Section titled “FetchClobPricesHistoryArgs”Properties
Section titled “Properties”
readonlyendTs:number
Window end in UNIX seconds.
fidelityMinutes
Section titled “fidelityMinutes”
readonlyfidelityMinutes:number
Bucket width in minutes — the unit the venue’s fidelity parameter takes.
startTs
Section titled “startTs”
readonlystartTs:number
Window start in UNIX seconds.
FetchDataApiTradesArgs
Section titled “FetchDataApiTradesArgs”Properties
Section titled “Properties”limit?
Section titled “limit?”
readonlyoptionallimit:number
Rows requested per page. Default 500.
FetchGammaKeysetArgs
Section titled “FetchGammaKeysetArgs”Properties
Section titled “Properties”active?
Section titled “active?”
readonlyoptionalactive:boolean
Tri-state active hint, with the same omit-vs-explicit-false contract.
closed?
Section titled “closed?”
readonlyoptionalclosed:boolean
Tri-state settled/unsettled hint. undefined omits the filter entirely
(the endpoint’s own default applies) while false sends an explicit
false — those are different requests.
limit?
Section titled “limit?”
readonlyoptionallimit:number
Rows requested per page. Default 100.
FetchKalshiCandlesticksArgs
Section titled “FetchKalshiCandlesticksArgs”Properties
Section titled “Properties”
readonlyendTs:number
periodIntervalMinutes
Section titled “periodIntervalMinutes”
readonlyperiodIntervalMinutes:number
Bucket size in MINUTES (Kalshi documents 1, 60, 1440).
startTs
Section titled “startTs”
readonlystartTs:number
FetchKalshiEventsArgs
Section titled “FetchKalshiEventsArgs”Properties
Section titled “Properties”limit?
Section titled “limit?”
readonlyoptionallimit:number
seriesTicker?
Section titled “seriesTicker?”
readonlyoptionalseriesTicker:string
status?
Section titled “status?”
readonlyoptionalstatus:string
Upstream-validated status filter. Anything else returns HTTP 400.
withNestedMarkets?
Section titled “withNestedMarkets?”
readonlyoptionalwithNestedMarkets:boolean
FetchKalshiMarketsArgs
Section titled “FetchKalshiMarketsArgs”Properties
Section titled “Properties”category?
Section titled “category?”
readonlyoptionalcategory:string
eventTicker?
Section titled “eventTicker?”
readonlyoptionaleventTicker:string
limit?
Section titled “limit?”
readonlyoptionallimit:number
minCloseTs?
Section titled “minCloseTs?”
readonlyoptionalminCloseTs:number
Lower bound on the market close timestamp, UNIX seconds.
seriesTicker?
Section titled “seriesTicker?”
readonlyoptionalseriesTicker:string
status?
Section titled “status?”
readonlyoptionalstatus:string
Upstream-validated status filter. Anything else returns HTTP 400.
tickers?
Section titled “tickers?”
readonlyoptionaltickers: readonlystring[]
Explicit market tickers; sent comma-joined.
FetchKalshiSeriesArgs
Section titled “FetchKalshiSeriesArgs”Properties
Section titled “Properties”category?
Section titled “category?”
readonlyoptionalcategory:string
Category narrowing (e.g. "Economics") — the only narrowing upstream honors.
includeProductMetadata?
Section titled “includeProductMetadata?”
readonlyoptionalincludeProductMetadata:boolean
Ask upstream to inline product metadata.
FetchKalshiTradesArgs
Section titled “FetchKalshiTradesArgs”Properties
Section titled “Properties”limit?
Section titled “limit?”
readonlyoptionallimit:number
maxTs?
Section titled “maxTs?”
readonlyoptionalmaxTs:number
minTs?
Section titled “minTs?”
readonlyoptionalminTs:number
KalshiCandleOptions
Section titled “KalshiCandleOptions”Properties
Section titled “Properties”interval
Section titled “interval”
readonlyinterval:MarketInterval
marketId
Section titled “marketId”
readonlymarketId:string
The Kalshi ticker. Carried through as a string, always.
readonlytier:KalshiTier
Which tier produced raw. This selects the key spelling and becomes the
row’s source provenance tag — the two can never disagree.
KalshiCandlesArgs
Section titled “KalshiCandlesArgs”Properties
Section titled “Properties”fromTime
Section titled “fromTime”
readonlyfromTime:Date
Window start, inclusive.
interval
Section titled “interval”
readonlyinterval:MarketInterval
Bucket width: 1m | 1h | 1d.
toTime
Section titled “toTime”
readonlytoTime:Date
Window end.
KalshiEventsArgs
Section titled “KalshiEventsArgs”Properties
Section titled “Properties”
readonlyoptionalall:boolean
Accept every event the venue lists. Required when no other filter is given.
series?
Section titled “series?”
readonlyoptionalseries:string
Series ticker to narrow to (e.g. "KXHIGHNY").
status?
Section titled “status?”
readonlyoptionalstatus:string
One of open / closed / settled / unopened, validated pre-fetch.
KalshiMarketsArgs
Section titled “KalshiMarketsArgs”Properties
Section titled “Properties”
readonlyoptionalall:boolean
Accept the full unnarrowed universe. Required when no other filter is given.
category?
Section titled “category?”
readonlyoptionalcategory:string
Venue category to narrow to.
event?
Section titled “event?”
readonlyoptionalevent:string
Event ticker to narrow to (e.g. "KXHIGHNY-26MAY29").
historical?
Section titled “historical?”
readonlyoptionalhistorical:boolean
Read from the venue’s historical tier instead of the live one, for markets
that closed before the live retention window. Requires series — that tier
reaches back far enough that an unnarrowed walk of it is exactly the bulk
retrieval the venue’s terms bar. Rows come back stamped
source: "kalshi.historical".
series?
Section titled “series?”
readonlyoptionalseries:string
Series ticker to narrow to (e.g. "KXHIGHNY").
status?
Section titled “status?”
readonlyoptionalstatus:string
One of open / closed / settled / unopened, validated pre-fetch.
KalshiOrderbookArgs
Section titled “KalshiOrderbookArgs”Properties
Section titled “Properties”depth?
Section titled “depth?”
readonlyoptionaldepth:number
Levels per side to request. Default 50; the venue accepts [1, 1000].
KalshiRef
Section titled “KalshiRef”What a Kalshi reference string actually identified.
level is derived from the URL shape, never guessed: a series link carries
no market ticker, so coercing one out of it would be the silent-wrong-
identifier failure. ticker is populated only at level === "market".
Properties
Section titled “Properties”eventSlug
Section titled “eventSlug”
readonlyeventSlug:null|string
readonlylevel:"event"|"series"|"market"
series
Section titled “series”
readonlyseries:null|string
ticker
Section titled “ticker”
readonlyticker:null|string
KalshiSeriesArgs
Section titled “KalshiSeriesArgs”Properties
Section titled “Properties”
readonlyoptionalall:boolean
Accept the full unnarrowed catalog. Required when category is omitted.
category?
Section titled “category?”
readonlyoptionalcategory:string
Venue category to narrow to (e.g. "Economics").
KalshiTradeOptions
Section titled “KalshiTradeOptions”Properties
Section titled “Properties”marketId
Section titled “marketId”
readonlymarketId:string
readonlytier:KalshiTier
KalshiTradesArgs
Section titled “KalshiTradesArgs”Properties
Section titled “Properties”fromTime
Section titled “fromTime”
readonlyfromTime:Date
Window start, inclusive.
toTime
Section titled “toTime”
readonlytoTime:Date
Window end, exclusive — rows at exactly toTime fall outside the window.
MarketCandleRow
Section titled “MarketCandleRow”One OHLC bucket — schema.markets.candles.v2, 23 columns.
Kalshi always returns the full column set (trade OHLC + bid OHLC + ask OHLC + volume + open interest) because bid/ask is often the only signal on an illiquid market. Polymarket serves a last price per bucket only, so its bid/ask, volume and open-interest columns are null — one shared column set keeps a cross-venue concatenation meaningful, and null means exactly “the venue served nothing”, never zero.
Properties
Section titled “Properties”ask_close
Section titled “ask_close”
readonlyask_close:null|number
ask_high
Section titled “ask_high”
readonlyask_high:null|number
ask_low
Section titled “ask_low”
readonlyask_low:null|number
ask_open
Section titled “ask_open”
readonlyask_open:null|number
Kalshi yes_ask OHLC; null on Polymarket — probability in [0,1].
bid_close
Section titled “bid_close”
readonlybid_close:null|number
bid_high
Section titled “bid_high”
readonlybid_high:null|number
bid_low
Section titled “bid_low”
readonlybid_low:null|number
bid_open
Section titled “bid_open”
readonlybid_open:null|number
Kalshi yes_bid OHLC; null on Polymarket — probability in [0,1].
bucket_start_utc
Section titled “bucket_start_utc”
readonlybucket_start_utc:string
Bucket start as an ISO-8601 UTC instant. Kalshi serves end_period_ts
(the period end) and is normalized to the start; the Polymarket CLOB t
field is already a bucket start.
readonlyclose:null|number
close_native
Section titled “close_native”
readonlyclose_native:null|number
readonlyhigh:null|number
high_native
Section titled “high_native”
readonlyhigh_native:null|number
interval
Section titled “interval”
readonlyinterval:MarketInterval
readonlylow:null|number
low_native
Section titled “low_native”
readonlylow_native:null|number
market_id
Section titled “market_id”
readonlymarket_id:string
Kalshi ticker | Polymarket CLOB token id. Always a string.
readonlyopen:null|number
Trade OHLC — probability in [0,1].
open_interest
Section titled “open_interest”
readonlyopen_interest:null|number
Units: contracts. Open contracts at bucket close. Kalshi only.
open_native
Section titled “open_native”
readonlyopen_native:null|number
Venue-native price. Kalshi cents, with sub-cent price tiers preserved as fractional cents; on Polymarket the native unit is already probability, so this equals the probability column.
source
Section titled “source”
readonlysource:MarketDataSource
readonlyvenue:MarketVenue
volume_contracts
Section titled “volume_contracts”
readonlyvolume_contracts:null|number
Units: contracts. Contracts traded in the bucket. Kalshi only: null on Polymarket — the venue serves no candle volume, and absent is not zero.
MarketDataClientOptions
Section titled “MarketDataClientOptions”Properties
Section titled “Properties”baseUrl?
Section titled “baseUrl?”
readonlyoptionalbaseUrl:string
Override the Kalshi API base.
Security: this override exists for tests and proxies, and its value is the caller’s own responsibility. No user-supplied string ever reaches it implicitly — a pasted kalshi.com link is parsed offline for its ticker and the request is then built from the manifest-resolved base (fallback KALSHI_API_BASE), so a lookalike host cannot steer a request anywhere. When set, this override wins over the manifest.
fetchImpl()?
Section titled “fetchImpl()?”
readonlyoptionalfetchImpl: (input,init?) =>Promise<Response>(input,init?) =>Promise<Response>
Inject fetch for tests or for a proxy wrapper. Defaults to global fetch.
Parameters
Section titled “Parameters”URL | RequestInfo
RequestInit
Returns
Section titled “Returns”Promise<Response>
Parameters
Section titled “Parameters”string | URL | Request
RequestInit
Returns
Section titled “Returns”Promise<Response>
maxPages?
Section titled “maxPages?”
readonlyoptionalmaxPages:number
Safety cap on pages walked per cursor-paginated call. Default 10 000.
signal?
Section titled “signal?”
readonlyoptionalsignal:AbortSignal
Abort the whole call. Threaded into every fetch this module issues.
sleepBetweenMs?
Section titled “sleepBetweenMs?”
readonlyoptionalsleepBetweenMs:number
Politeness sleep between requests in ms. Default 100. Pass 0 to skip.
sleepImpl()?
Section titled “sleepImpl()?”
readonlyoptionalsleepImpl: (ms,signal?) =>Promise<void>
Injectable sleep. Defaults to a real setTimeout sleep; tests inject a
recorder so a capped Retry-After can be asserted without actually waiting
two minutes.
Parameters
Section titled “Parameters”number
signal?
Section titled “signal?”AbortSignal
Returns
Section titled “Returns”Promise<void>
timeoutMs?
Section titled “timeoutMs?”
readonlyoptionaltimeoutMs:number
Per-attempt request timeout in ms. Default 30 000.
Without one, a server that accepts the connection and then never answers
pins the call forever — fetch has no timeout of its own. Each attempt gets
its own AbortController, cleared in a finally, and the caller’s own
signal is composed onto it: aborting the caller aborts the attempt, and
the timeout aborts only the attempt it belongs to. (Composed by listener
rather than AbortSignal.any, which is not available everywhere this
bundles.)
userAgent?
Section titled “userAgent?”
readonlyoptionaluserAgent:string
Override the User-Agent. Defaults to core’s userAgent() — never a literal.
MarketEventRow
Section titled “MarketEventRow”One event — schema.markets.events.v1, 10 columns.
Properties
Section titled “Properties”close_time
Section titled “close_time”
readonlyclose_time:null|string
Event close instant as an ISO-8601 UTC string.
event_id
Section titled “event_id”
readonlyevent_id:null|string
Kalshi event_ticker | Polymarket event id. Always a string when present;
null when the venue served no id on the record.
event_slug
Section titled “event_slug”
readonlyevent_slug:null|string
Polymarket URL slug; Kalshi repeats its event_ticker here.
market_count
Section titled “market_count”
readonlymarket_count:null|number
Number of markets under the event as served.
open_time
Section titled “open_time”
readonlyopen_time:null|string
Event open instant as an ISO-8601 UTC string.
series_ticker
Section titled “series_ticker”
readonlyseries_ticker:null|string
Kalshi only. Null on Polymarket — the venue has no series tier.
source
Section titled “source”
readonlysource:MarketDataSource
status
Section titled “status”
readonlystatus:null|string
Normalized status: open | closed | settled | unopened.
readonlytitle:null|string
readonlyvenue:MarketVenue
MarketListingRow
Section titled “MarketListingRow”One market’s metadata — schema.markets.listing.v1, 19 columns.
Properties
Section titled “Properties”best_ask
Section titled “best_ask”
readonlybest_ask:null|number
Top-of-book ask — probability in [0,1].
best_bid
Section titled “best_bid”
readonlybest_bid:null|number
Top-of-book bid — probability in [0,1].
close_time
Section titled “close_time”
readonlyclose_time:null|string
Market close instant as an ISO-8601 UTC string.
event_id
Section titled “event_id”
readonlyevent_id:null|string
Parent event: Kalshi event_ticker | Polymarket event id.
last_price
Section titled “last_price”
readonlylast_price:null|number
Last traded price — probability in [0,1].
liquidity_usd
Section titled “liquidity_usd”
readonlyliquidity_usd:null|number
Units: USD. Resting book value. Polymarket only (Gamma liquidityNum).
market_id
Section titled “market_id”
readonlymarket_id:null|string
Kalshi ticker | Polymarket Gamma market id. Always a string when present; null when the venue served no id on the record. A listing is a browse, so one malformed market reads null rather than taking the page down with it.
market_slug
Section titled “market_slug”
readonlymarket_slug:null|string
Polymarket URL slug; null on Kalshi.
open_interest
Section titled “open_interest”
readonlyopen_interest:null|number
Units: contracts. Open contracts. Kalshi only.
open_time
Section titled “open_time”
readonlyopen_time:null|string
Market open instant as an ISO-8601 UTC string.
outcome_token_ids
Section titled “outcome_token_ids”
readonlyoutcome_token_ids:null|string
Comma-joined Polymarket CLOB token ids, kept as strings — 77-digit ids lose precision if read as numbers. Null on Kalshi.
outcomes
Section titled “outcomes”
readonlyoutcomes:null|string
Comma-joined outcome names (Kalshi is always yes,no).
series_ticker
Section titled “series_ticker”
readonlyseries_ticker:null|string
Kalshi only. Null on Polymarket — the venue has no series tier.
source
Section titled “source”
readonlysource:MarketDataSource
status
Section titled “status”
readonlystatus:null|string
Normalized status: open | closed | settled | unopened.
readonlytitle:null|string
Kalshi title | Polymarket question.
readonlyvenue:MarketVenue
volume_contracts
Section titled “volume_contracts”
readonlyvolume_contracts:null|number
Units: contracts. Lifetime contracts traded. Kalshi only.
volume_usd
Section titled “volume_usd”
readonlyvolume_usd:null|number
Units: USD. Lifetime notional. Polymarket only (Gamma volumeNum) and
venue-served, not computed here. Null on Kalshi.
MarketOrderbookRow
Section titled “MarketOrderbookRow”One book level, long format — schema.markets.orderbook.v2, 9 columns.
Kalshi quotes its book as YES bids and NO bids; the normalizer maps the NO
side onto the yes-token ask by ask_price = 1 - no_bid_price, so both venues
speak one vocabulary and a Kalshi book compares directly to a Polymarket one.
Properties
Section titled “Properties”captured_at
Section titled “captured_at”
readonlycaptured_at:string
Snapshot instant as an ISO-8601 UTC string — the client clock for Kalshi (the venue stamps no book time), the venue timestamp for Polymarket.
readonlylevel:number
Depth rank: 0 = best (top of book), increasing away from the touch.
market_id
Section titled “market_id”
readonlymarket_id:string
Kalshi ticker | Polymarket CLOB token id. Always a string.
readonlyprice:null|number
Probability in [0,1].
price_native
Section titled “price_native”
readonlyprice_native:null|number
Venue-native price — Kalshi cents; on Polymarket equal to price.
readonlyside:MarketBookSide
size_contracts
Section titled “size_contracts”
readonlysize_contracts:null|number
Units: contracts. Resting size at this level.
source
Section titled “source”
readonlysource:MarketDataSource
readonlyvenue:MarketVenue
MarketSeriesRow
Section titled “MarketSeriesRow”One recurring-contract family — schema.markets.series.v1, 7 columns.
Kalshi only. Polymarket has no series tier at all, which is why
polymarket.series() raises VenueCapabilityError rather than returning an
empty frame that would read as “this venue has no series right now”.
Properties
Section titled “Properties”category
Section titled “category”
readonlycategory:null|string
Venue category — the value the category= filter matches.
frequency
Section titled “frequency”
readonlyfrequency:null|string
Recurrence cadence as served by the venue.
series_ticker
Section titled “series_ticker”
readonlyseries_ticker:null|string
The recurring-contract identifier (e.g. the NHIGH family stem). Null when the venue served no ticker on the record: a browse must not fail on one malformed row.
settlement_sources
Section titled “settlement_sources”
readonlysettlement_sources:null|string
Comma-joined venue settlement source names.
source
Section titled “source”
readonlysource:MarketDataSource
readonlytitle:null|string
readonlyvenue:MarketVenue
Always kalshi — Polymarket has no series tier.
MarketTradeRow
Section titled “MarketTradeRow”One executed trade — schema.markets.trades.v2, 10 columns.
Properties
Section titled “Properties”market_id
Section titled “market_id”
readonlymarket_id:null|string
Kalshi ticker | Polymarket CLOB token id. Always a string when present, and
nullable here unlike on the candle row: Polymarket’s Data-API interleaves
every outcome of a market and each row carries its own asset, so a row
served without one keeps a null id rather than borrowing its neighbour’s —
which would attribute a NO print to the YES token.
readonlyprice:null|number
Probability in [0,1]. On Kalshi this is the YES price.
price_native
Section titled “price_native”
readonlyprice_native:null|number
Venue-native price — Kalshi cents; on Polymarket equal to price.
readonlyside:null|string
Normalized lowercase outcome taken: yes | no on Kalshi, the outcome label on Polymarket.
size_contracts
Section titled “size_contracts”
readonlysize_contracts:null|number
Units: contracts. Shares/contracts traded.
source
Section titled “source”
readonlysource:MarketDataSource
trade_id
Section titled “trade_id”
readonlytrade_id:null|string
Kalshi trade_id | Polymarket transactionHash.
traded_at
Section titled “traded_at”
readonlytraded_at:string
Trade instant as an ISO-8601 UTC string.
readonlyvenue:MarketVenue
volume_usd
Section titled “volume_usd”
readonlyvolume_usd:null|number
Units: USD. Polymarket only, and derived as size_contracts * price — the
venue serves no such field. Null on Kalshi, which publishes no USD notional
for a fill and where inventing one would be a fabricated number.
PolymarketCandleOptions
Section titled “PolymarketCandleOptions”Properties
Section titled “Properties”interval
Section titled “interval”
readonlyinterval:MarketInterval
marketId
Section titled “marketId”
readonlymarketId:string
The CLOB token id. Carried through as a string, always.
PolymarketCandlesArgs
Section titled “PolymarketCandlesArgs”Properties
Section titled “Properties”fromTime
Section titled “fromTime”
readonlyfromTime:Date
Window start, inclusive.
interval
Section titled “interval”
readonlyinterval:MarketInterval
Bucket width: 1m | 1h | 1d.
readonlyside:string
The outcome to price, matched case-insensitively against the market’s own.
toTime
Section titled “toTime”
readonlytoTime:Date
Window end, exclusive.
PolymarketDataClientOptions
Section titled “PolymarketDataClientOptions”Properties
Section titled “Properties”clobBaseUrl?
Section titled “clobBaseUrl?”
readonlyoptionalclobBaseUrl:string
Override the CLOB base. Same contract as gammaBaseUrl.
dataBaseUrl?
Section titled “dataBaseUrl?”
readonlyoptionaldataBaseUrl:string
Override the Data-API base. Same contract as gammaBaseUrl.
fetchImpl()?
Section titled “fetchImpl()?”
readonlyoptionalfetchImpl: (input,init?) =>Promise<Response>(input,init?) =>Promise<Response>
Inject fetch for tests or for a proxy wrapper. Defaults to global fetch.
Parameters
Section titled “Parameters”URL | RequestInfo
RequestInit
Returns
Section titled “Returns”Promise<Response>
Parameters
Section titled “Parameters”string | URL | Request
RequestInit
Returns
Section titled “Returns”Promise<Response>
gammaBaseUrl?
Section titled “gammaBaseUrl?”
readonlyoptionalgammaBaseUrl:string
Override the Gamma base.
Security: this override exists for tests and proxies, and its value is the caller’s own responsibility. No user-supplied string ever reaches it implicitly — a pasted polymarket.com link is parsed offline for its slug and the request is then built from the manifest-resolved base (fallback GAMMA_API_BASE), so a lookalike host cannot steer a request anywhere. When set, this override wins over the manifest.
maxPages?
Section titled “maxPages?”
readonlyoptionalmaxPages:number
Safety cap on pages walked per paginated call. Default 10 000.
signal?
Section titled “signal?”
readonlyoptionalsignal:AbortSignal
Abort the whole call. Threaded into every fetch this module issues.
sleepBetweenMs?
Section titled “sleepBetweenMs?”
readonlyoptionalsleepBetweenMs:number
Politeness sleep between requests in ms. Default 200. Pass 0 to skip.
sleepImpl()?
Section titled “sleepImpl()?”
readonlyoptionalsleepImpl: (ms,signal?) =>Promise<void>
Injectable sleep. Defaults to a real setTimeout sleep; tests inject a
recorder so a capped Retry-After can be asserted without actually waiting
two minutes.
Parameters
Section titled “Parameters”number
signal?
Section titled “signal?”AbortSignal
Returns
Section titled “Returns”Promise<void>
timeoutMs?
Section titled “timeoutMs?”
readonlyoptionaltimeoutMs:number
Per-attempt request timeout in ms. Default 30 000.
Without one, a server that accepts the connection and then never answers
pins the call forever — fetch has no timeout of its own, and in a browser
tab that is a spinner that never stops. Each attempt gets its own
AbortController, cleared in a finally, and the caller’s own signal is
composed onto it by listener (AbortSignal.any is not available everywhere
this bundles).
PolymarketEventsArgs
Section titled “PolymarketEventsArgs”Properties
Section titled “Properties”
readonlyoptionalall:boolean
Accept every event the venue lists. Required when no other filter is given.
event?
Section titled “event?”
readonlyoptionalevent:string
An event slug or a pasted polymarket.com event link, parsed offline.
status?
Section titled “status?”
readonlyoptionalstatus:string
One of open / closed / settled / unopened, validated pre-fetch.
PolymarketMarketsArgs
Section titled “PolymarketMarketsArgs”Properties
Section titled “Properties”
readonlyoptionalall:boolean
Accept the full unnarrowed universe. Required when no other filter is given.
event?
Section titled “event?”
readonlyoptionalevent:string
An event slug or a pasted polymarket.com event link, parsed offline.
status?
Section titled “status?”
readonlyoptionalstatus:string
One of open / closed / settled / unopened, validated pre-fetch.
PolymarketOrderbookArgs
Section titled “PolymarketOrderbookArgs”Properties
Section titled “Properties”
readonlyside:string
The outcome whose book to snapshot, matched case-insensitively.
PolymarketRef
Section titled “PolymarketRef”What a Polymarket reference string actually identified.
slug is the identifier the link points at (the market slug for a market
link, the event slug for an event link); eventSlug is the owning event when
the link carried one, else null — a /market/{slug} shortlink carries no
event context.
Properties
Section titled “Properties”eventSlug
Section titled “eventSlug”
readonlyeventSlug:null|string
readonlylevel:"event"|"market"
readonlyslug:string
PolymarketTradeOptions
Section titled “PolymarketTradeOptions”Properties
Section titled “Properties”marketId
Section titled “marketId”
readonlymarketId:string
PolymarketTradesArgs
Section titled “PolymarketTradesArgs”Properties
Section titled “Properties”fromTime
Section titled “fromTime”
readonlyfromTime:Date
Window start, inclusive.
readonlyoptionalside:string
Keep only this outcome, matched case-insensitively. Omit for every side.
toTime
Section titled “toTime”
readonlytoTime:Date
Window end, exclusive — a trade at exactly toTime falls outside.
RequireNarrowingOptions
Section titled “RequireNarrowingOptions”Properties
Section titled “Properties”
readonlyall:boolean
The caller’s explicit full-sweep opt-in.
readonlyverb:string
The public verb name, for the message.
ResolvedSide
Section titled “ResolvedSide”Both identifiers a price verb needs, returned together so neither is guessed.
Properties
Section titled “Properties”conditionId
Section titled “conditionId”
readonlyconditionId:string
The Gamma condition id — what the Data-API /trades addresses by.
tokenId
Section titled “tokenId”
readonlytokenId:string
The CLOB token id — what /prices-history and /book address by.
UnsupportedResolutionErrorOptions
Section titled “UnsupportedResolutionErrorOptions”Extends
Section titled “Extends”ContractErrorOptions
Properties
Section titled “Properties”interval?
Section titled “interval?”
optionalinterval:null|string
The rejected interval value exactly as the caller passed it.
supported?
Section titled “supported?”
optionalsupported:null|Iterable<string,any,any>
The venue’s supported set. Normalised to string[] on the instance.
venue?
Section titled “venue?”
optionalvenue:null|string
The venue whose set was violated ("kalshi" / "polymarket").
VenueCapabilityErrorOptions
Section titled “VenueCapabilityErrorOptions”Extends
Section titled “Extends”ContractErrorOptions
Properties
Section titled “Properties”capability?
Section titled “capability?”
optionalcapability:null|string
The grammar verb / concept the venue has no analog for ("series").
remedy?
Section titled “remedy?”
optionalremedy:null|string
What to call instead ("use events()") — the teaching remedy.
venue?
Section titled “venue?”
optionalvenue:null|string
The venue lacking the capability.
Type Aliases
Section titled “Type Aliases”KalshiTier
Section titled “KalshiTier”KalshiTier:
"kalshi"|"kalshi.historical"
The Kalshi source identities this module emits.
MarketBookSide
Section titled “MarketBookSide”MarketBookSide:
"bid"|"ask"
Book side of the YES token. Mirrors the schema.markets.orderbook.v2 enum.
MarketDataSchemaId
Section titled “MarketDataSchemaId”MarketDataSchemaId: typeof
MARKET_DATA_SCHEMA_IDS[keyof typeofMARKET_DATA_SCHEMA_IDS]
The id string of any of the six market-data schemas.
MarketDataSource
Section titled “MarketDataSource”MarketDataSource:
"kalshi"|"kalshi.historical"|"polymarket.gamma"|"polymarket.clob"|"polymarket.data"
Per-row source identity. The dotted suffix names the tier, following the
cli/cli.archive and cwop.live/cwop.cache idiom already in the SDK:
a consumer reading a concatenated frame can see which endpoint served each
row without a second column.
kalshi— the live Kalshi trade API.kalshi.historical— the Kalshi/historicaltier (a different wire vocabulary for the same semantics; seenormalize.ts).polymarket.gamma— Gamma market/event metadata.polymarket.clob— the CLOB price-history and book endpoints.polymarket.data— the Data-API trade tape.
MarketInterval
Section titled “MarketInterval”MarketInterval:
"1m"|"1h"|"1d"
Supported candle bucket widths. Mirrors Python _normalize.INTERVALS.
MarketVenue
Section titled “MarketVenue”MarketVenue:
"kalshi"|"polymarket"
The venue a row belongs to — the venue column.
NormalizedCandleRow
Section titled “NormalizedCandleRow”NormalizedCandleRow:
Omit<MarketCandleRow,"bucket_start_utc"> &object
A candle row as it leaves the normalizer, before schema validation.
Type declaration
Section titled “Type declaration”bucket_start_utc
Section titled “bucket_start_utc”
readonlybucket_start_utc:string|null
NormalizedOrderbookRow
Section titled “NormalizedOrderbookRow”NormalizedOrderbookRow:
MarketOrderbookRow
A book level as it leaves the normalizer. captured_at is always known.
NormalizedTradeRow
Section titled “NormalizedTradeRow”NormalizedTradeRow:
Omit<MarketTradeRow,"traded_at"> &object
A trade row as it leaves the normalizer, before schema validation.
Type declaration
Section titled “Type declaration”traded_at
Section titled “traded_at”
readonlytraded_at:string|null
Variables
Section titled “Variables”CLOB_API_BASE
Section titled “CLOB_API_BASE”
constCLOB_API_BASE:"https://clob.polymarket.com"="https://clob.polymarket.com"
Polymarket CLOB API base — a separate host from Gamma, hosting
/prices-history and /book. The market query parameter on
/prices-history is the CLOB token id (the ERC-1155 asset id), not the Gamma
market or condition id. Kept as a module-level literal because it is both a
public export (do not remove) and the fallback argument resolveSourceUrl
uses when the resolved catalog has no usable entry for "markets.polymarket_clob".
Resolution happens at call time inside the CLOB fetchers (opts.clobBaseUrl
winning over the manifest), never here at module scope.
DATA_API_BASE
Section titled “DATA_API_BASE”
constDATA_API_BASE:"https://data-api.polymarket.com"="https://data-api.polymarket.com"
Polymarket Data-API base — a third host, distinct from both Gamma and CLOB,
serving the executed-trade tape at /trades. Its market query parameter
takes the Gamma conditionId, not a CLOB token id — the exact reverse of the
CLOB /prices-history parameter of the same name. Passing the wrong one
returns an empty array rather than an error, so the two are worth keeping
straight at the call site. Kept as a module-level literal because it is both a
public export (do not remove) and the fallback argument resolveSourceUrl
uses when the resolved catalog has no usable entry for "markets.polymarket_data".
Resolution happens at call time inside fetchDataApiTrades (once, before its
offset loop; opts.dataBaseUrl winning over the manifest), never here at
module scope.
GAMMA_API_BASE
Section titled “GAMMA_API_BASE”
constGAMMA_API_BASE:"https://gamma-api.polymarket.com"="https://gamma-api.polymarket.com"
Polymarket Gamma API base — read-only public REST, keyless. Hosts
/markets/keyset, /events/keyset, /markets/slug/{slug}, and
/events/slug/{slug}. Kept as a module-level literal because it is both a
public export (do not remove) and the fallback argument resolveSourceUrl
uses when the resolved catalog has no usable entry for "markets.polymarket_gamma".
Resolution happens at call time inside the Gamma fetchers (once per outer
call, opts.gammaBaseUrl winning over the manifest), never here at module
scope.
GAMMA_CURSOR_PARAM
Section titled “GAMMA_CURSOR_PARAM”
constGAMMA_CURSOR_PARAM:"after_cursor"="after_cursor"
The only request parameter that advances a Gamma keyset walk.
A keyset response carries its continuation token under next_cursor, so the
two obvious spellings to echo back are cursor and next_cursor. Both were
probed against the real endpoint: each returns HTTP 200 carrying the first
page again, with the same row ids, forever. Only after_cursor moves the
window. A loop built on either of the other two never terminates and never
errors, which is why this is a named constant rather than an inline string,
and why the walk also breaks when a page yields zero new ids.
KALSHI_API_BASE
Section titled “KALSHI_API_BASE”
constKALSHI_API_BASE:"https://api.elections.kalshi.com/trade-api/v2"="https://api.elections.kalshi.com/trade-api/v2"
Kalshi’s public REST base. Kept as a module-level literal because it is both a
public export (do not remove) and the fallback argument resolveSourceUrl
uses when the resolved catalog has no usable entry for "markets.kalshi". Resolution
happens at call time inside each public fetcher (via resolveKalshiBase, once
per outer call, threaded through pagination), never here at module scope. The
./trades twin keeps its own copy, but both halves pass the same
"markets.kalshi" key, so one catalog edit repoints both at once; only the
fallback literal below is per-file.
KALSHI_CANDLE_CHUNK_BUCKETS
Section titled “KALSHI_CANDLE_CHUNK_BUCKETS”
constKALSHI_CANDLE_CHUNK_BUCKETS:4500=4500
The bucket count chunkWindow actually targets. The ~10% margin below KALSHI_MAX_CANDLES_PER_REQUEST exists so a boundary rounding (the server counting one bucket more than the client does at a chunk edge) can never trip the server cap.
KALSHI_HISTORICAL_PATH_PREFIX
Section titled “KALSHI_HISTORICAL_PATH_PREFIX”
constKALSHI_HISTORICAL_PATH_PREFIX:"/historical"="/historical"
Path prefix for Kalshi’s historical tier — a path, not a second host.
Verified 30 July 2026: /historical/* is served by the same host as the live
tier, so one base URL with path-only variation covers both.
KALSHI_MARKET_URL_HOSTS
Section titled “KALSHI_MARKET_URL_HOSTS”
constKALSHI_MARKET_URL_HOSTS:ReadonlySet<string>
Hosts whose market links this module will parse for Kalshi.
KALSHI_MARKET_URL_RE
Section titled “KALSHI_MARKET_URL_RE”
constKALSHI_MARKET_URL_RE:RegExp
A kalshi.com market link. Path is /markets/{series} with an OPTIONAL second
{event-title-slug} segment and nothing after it — a third segment is
rejected even though the site soft-renders one. The per-market identity rides
in the ?ticker= query param, extracted separately below.
KALSHI_MAX_CANDLES_PER_REQUEST
Section titled “KALSHI_MAX_CANDLES_PER_REQUEST”
constKALSHI_MAX_CANDLES_PER_REQUEST:5000=5000
Kalshi’s per-request candlestick cap. Exceeding it is a hard HTTP 400 — no partial result, no silent truncation.
KALSHI_TICKER_RE
Section titled “KALSHI_TICKER_RE”
constKALSHI_TICKER_RE:RegExp
A Kalshi ticker: uppercase alphanumeric segments joined by - or . (the
. appears in between-market strikes such as ...-B88.5). The first segment
is required; /, ?, #, whitespace, and any lowercase or non-ASCII
character are outside the class and cannot match.
KALSHI_TIER_HISTORICAL
Section titled “KALSHI_TIER_HISTORICAL”
constKALSHI_TIER_HISTORICAL:"kalshi.historical"="kalshi.historical"
Source identity for a row read from Kalshi’s /historical tier. The
dotted-suffix idiom mirrors cli/cli.archive and cwop.live/cwop.cache:
a consumer joining a concatenated frame sees which tier served each row
without a second column.
KALSHI_TIER_LIVE
Section titled “KALSHI_TIER_LIVE”
constKALSHI_TIER_LIVE:"kalshi"="kalshi"
Source identity for a row read from Kalshi’s live tier.
KALSHI_VENUE
Section titled “KALSHI_VENUE”
constKALSHI_VENUE:MarketVenue="kalshi"
Venue tag for Kalshi rows (both tiers).
MARKET_DATA_SCHEMA_IDS
Section titled “MARKET_DATA_SCHEMA_IDS”
constMARKET_DATA_SCHEMA_IDS:object
The six market-data wire schema ids, keyed by TS verb label.
Type declaration
Section titled “Type declaration”candle
Section titled “candle”
readonlycandle:"schema.markets.candles.v2"="schema.markets.candles.v2"
readonlyevent:"schema.markets.events.v1"="schema.markets.events.v1"
listing
Section titled “listing”
readonlylisting:"schema.markets.listing.v1"="schema.markets.listing.v1"
orderbook
Section titled “orderbook”
readonlyorderbook:"schema.markets.orderbook.v2"="schema.markets.orderbook.v2"
series
Section titled “series”
readonlyseries:"schema.markets.series.v1"="schema.markets.series.v1"
readonlytrade:"schema.markets.trades.v2"="schema.markets.trades.v2"
MARKET_INTERVALS
Section titled “MARKET_INTERVALS”
constMARKET_INTERVALS:Readonly<Record<MarketInterval,number>>
Supported candle intervals -> bucket seconds. Mirrors Python INTERVALS
verbatim so a caller never has to learn two resolution vocabularies.
MAX_CANDLE_CHUNKS
Section titled “MAX_CANDLE_CHUNKS”
constMAX_CANDLE_CHUNKS:10000=10_000
Safety cap on the number of chunks chunkWindow will emit. A pathological window (decades at 1m) otherwise turns one call into an unbounded request storm against a public keyless endpoint.
MVE_FILTER_EXCLUDE
Section titled “MVE_FILTER_EXCLUDE”
constMVE_FILTER_EXCLUDE:"exclude"="exclude"
The only value this SDK ever sends for Kalshi’s mve_filter query parameter.
Probed 30 July 2026: mve_filter is not validated upstream —
mve_filter=bogus returns HTTP 200 with unfiltered results, in contrast to
status=, which is validated (HTTP 400 invalid status filter). A typo in a
caller-supplied value would therefore silently open the >400K
multivariate-event-combo universe instead of erroring. The mitigation is
structural rather than defensive: this is a module constant, and
fetchKalshiMarkets exposes no mveFilter parameter at all.
POLYMARKET_MARKET_URL_HOSTS
Section titled “POLYMARKET_MARKET_URL_HOSTS”
constPOLYMARKET_MARKET_URL_HOSTS:ReadonlySet<string>
Hosts whose market links this module will parse for Polymarket.
POLYMARKET_MARKET_URL_RE
Section titled “POLYMARKET_MARKET_URL_RE”
constPOLYMARKET_MARKET_URL_RE:RegExp
A polymarket.com market link. Two accepted path families:
/event/{event-slug}[/{market-slug}] — the canonical shape
/market/{market-slug} — the singular per-market shortlink
/markets/ (plural), /predictions/, /search and the site root are not
market routes and do not match.
POLYMARKET_SLUG_RE
Section titled “POLYMARKET_SLUG_RE”
constPOLYMARKET_SLUG_RE:RegExp
A Polymarket slug: lowercase alphanumeric segments joined by -. Same
exclusions as above, plus uppercase — polymarket.com hard-404s an uppercased
slug, so it is not an alias.
POLYMARKET_SOURCE_CLOB
Section titled “POLYMARKET_SOURCE_CLOB”
constPOLYMARKET_SOURCE_CLOB:MarketDataSource="polymarket.clob"
Source identity for Polymarket CLOB rows (/prices-history, /book).
POLYMARKET_SOURCE_DATA
Section titled “POLYMARKET_SOURCE_DATA”
constPOLYMARKET_SOURCE_DATA:MarketDataSource="polymarket.data"
Source identity for Polymarket Data-API rows (/trades).
POLYMARKET_SOURCE_GAMMA
Section titled “POLYMARKET_SOURCE_GAMMA”
constPOLYMARKET_SOURCE_GAMMA:MarketDataSource="polymarket.gamma"
Source identity for Polymarket Gamma rows (market/event metadata).
POLYMARKET_VENUE
Section titled “POLYMARKET_VENUE”
constPOLYMARKET_VENUE:MarketVenue="polymarket"
Venue tag for Polymarket rows.
Functions
Section titled “Functions”bucketStartFromPeriodEnd()
Section titled “bucketStartFromPeriodEnd()”bucketStartFromPeriodEnd(
endPeriodTs,intervalSeconds):null|Date
Convert a Kalshi end_period_ts into a UTC bucket start.
Kalshi stamps each candle with the period end; the canonical timestamp across both venues is the bucket start, so the interval is subtracted here once rather than at every call site. Returns null (never a fabricated epoch) when the payload’s timestamp is missing or unparseable.
Parameters
Section titled “Parameters”endPeriodTs
Section titled “endPeriodTs”unknown
intervalSeconds
Section titled “intervalSeconds”number
Returns
Section titled “Returns”null | Date
chunkWindow()
Section titled “chunkWindow()”chunkWindow(
fromTime,toTime,interval,maxBuckets): [number,number][]
Split [fromTime, toTime) into request windows under the venue cap.
Kalshi refuses any candlestick request whose window spans more than KALSHI_MAX_CANDLES_PER_REQUEST buckets with a hard HTTP 400 — no partial result, no silent truncation — so a month of 1m candles is not a single request. This function does the arithmetic once, in one place, and KALSHI_CANDLE_CHUNK_BUCKETS leaves a margin under the cap so a boundary rounding at a chunk edge can never trip it.
The returned chunks are contiguous and non-overlapping and tile the window
exactly: the first start is fromTime, the last end is toTime, and every
interior edge is shared. The caller is expected to request them sequentially
(the politeness floor lives in the client, not here) and to dedup on
bucket_start_utc after concatenating, because the venue may return the
bucket sitting on a shared edge in both adjacent chunks.
Parameters
Section titled “Parameters”fromTime
Section titled “fromTime”Date
toTime
Section titled “toTime”Date
interval
Section titled “interval”maxBuckets
Section titled “maxBuckets”number = KALSHI_CANDLE_CHUNK_BUCKETS
Returns
Section titled “Returns”[number, number][]
(startTs, endTs) pairs in UNIX seconds.
Throws
Section titled “Throws”a bound is not a valid Date, fromTime >= toTime,
maxBuckets < 1, or the window would need more than MAX_CANDLE_CHUNKS
requests.
Throws
Section titled “Throws”interval is outside MARKET_INTERVALS.
coerceGammaStringList()
Section titled “coerceGammaStringList()”coerceGammaStringList(
value):string[]
Coerce a Gamma polymorphic list field into a list of strings.
Gamma returns outcomes / clobTokenIds / outcomePrices sometimes as a
native list and sometimes as a JSON-encoded string ('["Yes", "No"]'). Both
forms are handled; anything else returns an empty list rather than throwing,
because a malformed metadata field must not take down a listing sweep.
Every element is coerced to a string. Token ids are 77-digit decimals: a numeric coercion would silently lose precision and every join against the id would then fail.
Parameters
Section titled “Parameters”unknown
Returns
Section titled “Returns”string[]
dollarStringToProbability()
Section titled “dollarStringToProbability()”dollarStringToProbability(
value):null|number
Parse a venue dollar string (e.g. "0.5500") into a probability.
Both Kalshi tiers and Polymarket express a price per contract in dollars in [0,1], which is the implied probability — so no scaling is applied here. Null, empty, and non-numeric inputs return null.
Parameters
Section titled “Parameters”unknown
Returns
Section titled “Returns”null | number
fetchClobBook()
Section titled “fetchClobBook()”fetchClobBook(
tokenId,opts):Promise<Record<string,unknown>>
Fetch the current CLOB order book for tokenId from /book.
Parameters
Section titled “Parameters”tokenId
Section titled “tokenId”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<Record<string, unknown>>
the book record carrying market (the condition id), asset_id,
timestamp (milliseconds, as a string), and the bids / asks level arrays.
fetchClobPricesHistory()
Section titled “fetchClobPricesHistory()”fetchClobPricesHistory(
tokenId,args,opts):Promise<Record<string,unknown>[]>
Fetch the CLOB price history for one token from /prices-history.
tokenId is a CLOB token id (the ERC-1155 asset id) — a decimal integer
roughly 77 digits long. It is carried as a string throughout and sent as a
query parameter, never concatenated into the path.
The endpoint serves {t, p} points and nothing else: no volume, no bid/ask,
no open interest. That absence is the reason the candle row’s
volume_contracts is null rather than zero downstream.
Parameters
Section titled “Parameters”tokenId
Section titled “tokenId”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
the raw price points; [] when the venue serves an empty history.
fetchDataApiTrades()
Section titled “fetchDataApiTrades()”fetchDataApiTrades(
conditionId,args,opts):Promise<Record<string,unknown>[]>
Fetch the executed-trade tape for conditionId from the Data-API.
market= on this endpoint takes the Gamma conditionId, not a CLOB token id
— the reverse of fetchClobPricesHistory. Passing a token id returns an
empty array rather than an error, so the two are worth keeping straight.
Pages by offset. Whether the host honours that parameter is not something
this client can assume, so the walk also stops when a page contributes zero
rows it has not already seen: a host that ignores the offset re-serves the
first page, and only the dedup guard ends that.
Parameters
Section titled “Parameters”conditionId
Section titled “conditionId”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
Remarks
Section titled “Remarks”Browser-direct — the Data-API answers
Access-Control-Allow-Origin: * plus Access-Control-Allow-Credentials: true.
fetchGammaEventBySlug()
Section titled “fetchGammaEventBySlug()”fetchGammaEventBySlug(
slug,opts):Promise<Record<string,unknown>>
Fetch one Gamma event by slug from /events/slug/{slug}.
The event-level companion to fetchGammaMarketBySlug; an event groups the markets a single question resolves across and carries them inline, so naming an event costs one request rather than a filtered walk.
Parameters
Section titled “Parameters”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<Record<string, unknown>>
fetchGammaEventsKeyset()
Section titled “fetchGammaEventsKeyset()”fetchGammaEventsKeyset(
args,opts):Promise<Record<string,unknown>[]>
List Gamma events through the cursor-paginated /events/keyset.
The same walk as fetchGammaMarketsKeyset against the event collection.
Parameters
Section titled “Parameters”FetchGammaKeysetArgs = {}
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
Remarks
Section titled “Remarks”Browser-direct — Gamma answers Access-Control-Allow-Origin: *.
fetchGammaMarketBySlug()
Section titled “fetchGammaMarketBySlug()”fetchGammaMarketBySlug(
slug,opts):Promise<Record<string,unknown>>
Fetch one Gamma market by slug from /markets/slug/{slug}.
The lookup behind “paste the link and tell me about this market”. The returned
record’s outcomes and clobTokenIds are JSON-string-encoded arrays handed
back exactly as received. It also carries conditionId, which is what the
Data-API trade tape addresses by.
Parameters
Section titled “Parameters”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<Record<string, unknown>>
Throws
Section titled “Throws”Gamma answers 404 for an unknown slug — “no such market” and “no data” are different answers and this client will not conflate them.
fetchGammaMarketsKeyset()
Section titled “fetchGammaMarketsKeyset()”fetchGammaMarketsKeyset(
args,opts):Promise<Record<string,unknown>[]>
List Gamma markets through the cursor-paginated /markets/keyset.
The successor to the legacy offset-paginated /markets, which caps at offset
10,000. Rows are returned raw: outcomes and clobTokenIds arrive
JSON-string-encoded and stay that way here — decoding them, and pairing an
outcome with its token id, belongs to the normalizer, which guards the
positional length match.
Parameters
Section titled “Parameters”FetchGammaKeysetArgs = {}
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
Remarks
Section titled “Remarks”Browser-direct — Gamma answers Access-Control-Allow-Origin: *.
fetchKalshiCandlesticks()
Section titled “fetchKalshiCandlesticks()”fetchKalshiCandlesticks(
ticker,args,opts):Promise<Record<string,unknown>[]>
Fetch OHLCV candlesticks from the live tier.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
fetchKalshiCandlesticksAnyTier()
Section titled “fetchKalshiCandlesticksAnyTier()”fetchKalshiCandlesticksAnyTier(
ticker,args,opts):Promise<[Record<string,unknown>[],MarketDataSource]>
Fetch candlesticks from whichever tier serves ticker.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<[Record<string, unknown>[], MarketDataSource]>
[rows, tier], where the rows keep their tier’s native field names —
the caller must normalize per tier.
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
fetchKalshiEvents()
Section titled “fetchKalshiEvents()”fetchKalshiEvents(
args,opts):Promise<Record<string,unknown>[]>
Fetch Kalshi events (GET /events), walking cursor pagination.
Parameters
Section titled “Parameters”Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
fetchKalshiHistoricalCandlesticks()
Section titled “fetchKalshiHistoricalCandlesticks()”fetchKalshiHistoricalCandlesticks(
ticker,args,opts):Promise<Record<string,unknown>[]>
Fetch candlesticks from the historical tier.
GET /historical/markets/{ticker}/candlesticks — note there is no
/series/{s} segment here, unlike the live tier.
The rows use different field names from the live tier (price.open vs
price.open_dollars, volume vs volume_fp) with the same semantics. They
are returned raw; tier-explicit normalization is the normalizer’s job, and
mixing the two shapes through one suffix-fallback chain produces silently
100x-wrong prices.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
fetchKalshiHistoricalMarket()
Section titled “fetchKalshiHistoricalMarket()”fetchKalshiHistoricalMarket(
ticker,opts):Promise<Record<string,unknown>>
Fetch one market from the historical tier
(GET /historical/markets/{ticker}), which serves the markets the live tier
answers 404 for.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<Record<string, unknown>>
fetchKalshiHistoricalMarkets()
Section titled “fetchKalshiHistoricalMarkets()”fetchKalshiHistoricalMarkets(
args,opts):Promise<Record<string,unknown>[]>
Fetch settled markets from the historical tier (GET /historical/markets).
seriesTicker is required, not optional: this tier reaches back past the live
retention window, and an unnarrowed walk of it is exactly the bulk retrieval
Kalshi’s Data Terms of Use bar.
Parameters
Section titled “Parameters”limit?
Section titled “limit?”number
seriesTicker
Section titled “seriesTicker”string
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
fetchKalshiHistoricalTrades()
Section titled “fetchKalshiHistoricalTrades()”fetchKalshiHistoricalTrades(
ticker,args,opts):Promise<Record<string,unknown>[]>
Fetch fills from the historical tier (GET /historical/trades).
Same row shape as the live tape. The confirmed parameter set is
ticker / limit / cursor only — this tier accepts no min_ts / max_ts
bounds, so the whole tape comes back and any time narrowing is the caller’s to
apply. Unsupported bounds are not forwarded: upstream would ignore them
silently and the caller would read a narrowing that never happened.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
limit?
Section titled “limit?”number
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
fetchKalshiMarket()
Section titled “fetchKalshiMarket()”fetchKalshiMarket(
ticker,opts):Promise<Record<string,unknown>>
Fetch the market object from the live tier (GET /markets/{ticker}).
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<Record<string, unknown>>
fetchKalshiMarketAnyTier()
Section titled “fetchKalshiMarketAnyTier()”fetchKalshiMarketAnyTier(
ticker,opts):Promise<[Record<string,unknown>,MarketDataSource]>
Fetch the market object from whichever tier serves ticker.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<[Record<string, unknown>, MarketDataSource]>
[market, tier].
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
fetchKalshiMarkets()
Section titled “fetchKalshiMarkets()”fetchKalshiMarkets(
args,opts):Promise<Record<string,unknown>[]>
Fetch Kalshi markets (GET /markets), walking cursor pagination.
Always sends mve_filter=exclude from MVE_FILTER_EXCLUDE. There is
deliberately no mveFilter field on FetchKalshiMarketsArgs — the
endpoint does not validate that parameter, so a caller typo would silently
open the >400K multivariate-event-combo universe rather than raising.
Parameters
Section titled “Parameters”Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
fetchKalshiOrderbook()
Section titled “fetchKalshiOrderbook()”fetchKalshiOrderbook(
ticker,args,opts):Promise<Record<string,unknown>>
Fetch the current book snapshot for ticker (GET /markets/{t}/orderbook).
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
depth?
Section titled “depth?”number
Returns
Section titled “Returns”Promise<Record<string, unknown>>
fetchKalshiOrderbooks()
Section titled “fetchKalshiOrderbooks()”fetchKalshiOrderbooks(
tickers,opts):Promise<Record<string,Record<string,unknown>>>
Fetch orderbooks for many tickers (GET /markets/orderbooks).
The batch sweep takes a comma-joined tickers= list, at most
ORDERBOOK_BATCH_SIZE per request. An empty list issues no request.
Parameters
Section titled “Parameters”tickers
Section titled “tickers”readonly string[]
Returns
Section titled “Returns”Promise<Record<string, Record<string, unknown>>>
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
fetchKalshiSeries()
Section titled “fetchKalshiSeries()”fetchKalshiSeries(
args,opts):Promise<Record<string,unknown>[]>
Fetch the Kalshi series catalog (GET /series).
This endpoint returns everything, in one response. Measured 30 July 2026:
12,330 series, 16,277,583 bytes uncompressed / 2.29 MB gzipped, in 0.66 s. It
ignores limit and returns no cursor, so there is nothing to paginate and no
server-side way to ask for less — category is the only narrowing that
actually shrinks the payload. No limit is sent, because sending one would
imply a narrowing that does not happen.
Parameters
Section titled “Parameters”Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
the series array; [] when upstream answers series: null.
Remarks
Section titled “Remarks”Node / server only — see the file header and
docs/market-data-browser-support.md.
fetchKalshiTrades()
Section titled “fetchKalshiTrades()”fetchKalshiTrades(
ticker,args,opts):Promise<Record<string,unknown>[]>
Fetch fills from the live tape (GET /markets/trades), cursor-paginated.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<Record<string, unknown>[]>
fetchKalshiTradesAnyTier()
Section titled “fetchKalshiTradesAnyTier()”fetchKalshiTradesAnyTier(
ticker,args,opts):Promise<[Record<string,unknown>[],MarketDataSource]>
Fetch fills from whichever tier serves ticker.
minTs / maxTs bound the live request only — the historical tape accepts no
time bounds, so a fallback returns the market’s whole tape and the caller
filters.
Parameters
Section titled “Parameters”ticker
Section titled “ticker”string
Returns
Section titled “Returns”Promise<[Record<string, unknown>[], MarketDataSource]>
[rows, tier].
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
kalshiCandles()
Section titled “kalshiCandles()”kalshiCandles(
urlOrId,args,opts):Promise<DataResult<MarketCandleRow>>
Fetch OHLC candles for one Kalshi market over a time window.
Kalshi refuses any candlestick request spanning more than 5,000 buckets with a
hard HTTP 400 — no partial result, no silent truncation — so a long window is
split into chunks under that cap and requested sequentially. Sequential, not
parallel: the client’s politeness floor only holds if the requests are actually
spaced, and a burst against a keyless public endpoint is exactly what a venue
rate-limits. The venue may serve the bucket sitting on a shared chunk edge in
both adjacent chunks, so rows are deduped on bucket_start_utc and sorted
ascending before they are stamped.
The tier is decided once, from the first chunk, and reused for every later
chunk. A frame never carries two provenances: if the live tier 404s, the
whole call routes to /historical and every row — plus the result’s
provenance.source — is stamped kalshi.historical. The two tiers spell the
same price legs differently, so a frame mixing them would carry silently
mis-scaled numbers with nothing in the data to reveal it.
The candle window is not half-open at the end. Every other windowed verb
in this SDK is [fromTime, toTime), but Kalshi’s end_ts is inclusive, so a
bucket whose period ends exactly at toTime comes back in the result. Read
bucket_start_utc if you are joining candles to a half-open tape: the last
bucket’s start is one interval before toTime.
The caller reaches Kalshi under their own relationship with the venue; this SDK sends no key and persists nothing.
Parameters
Section titled “Parameters”urlOrId
Section titled “urlOrId”string
Returns
Section titled “Returns”Promise<DataResult<MarketCandleRow>>
Throws
Section titled “Throws”either bound is not a valid Date.
Throws
Section titled “Throws”fromTime >= toTime.
Throws
Section titled “Throws”interval is outside 1m / 1h / 1d.
Throws
Section titled “Throws”urlOrId is not a Kalshi market reference.
Remarks
Section titled “Remarks”Node / server only — Kalshi 403s any non-kalshi.com Origin,
including chrome-extension:// and null, and 403s the preflight. A browser
or extension needs a proxy. See docs/market-data-browser-support.md.
kalshiEventRow()
Section titled “kalshiEventRow()”kalshiEventRow(
raw,source):MarketEventRow
Map one Kalshi event record onto the event column contract.
Parameters
Section titled “Parameters”Record<string, unknown>
source
Section titled “source”Returns
Section titled “Returns”kalshiEvents()
Section titled “kalshiEvents()”kalshiEvents(
args,opts):Promise<DataResult<MarketEventRow>>
List the events under a Kalshi series.
An event groups the markets that settle on one occurrence — one calendar day of a daily-high series, for instance — so this is the middle tier between kalshiSeries and kalshiMarkets.
Parameters
Section titled “Parameters”KalshiEventsArgs = {}
Returns
Section titled “Returns”Promise<DataResult<MarketEventRow>>
a schema.markets.events.v1 result with open_time / close_time as
ISO-8601 UTC instants. A query that matches nothing resolves to a zero-row
result with the same provenance stamp.
Throws
Section titled “Throws”no filter and no all: true, or an invalid status.
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
kalshiListingRow()
Section titled “kalshiListingRow()”kalshiListingRow(
raw,source):MarketListingRow
Map one Kalshi market record onto the listing column contract.
The Polymarket-only columns (market_slug, outcome_token_ids, volume_usd,
liquidity_usd) are null here rather than filled with a plausible Kalshi
substitute: the venue serves no such value, and absent is not zero.
Parameters
Section titled “Parameters”Record<string, unknown>
source
Section titled “source”Returns
Section titled “Returns”kalshiMarket()
Section titled “kalshiMarket()”kalshiMarket(
urlOrId,opts):Promise<DataResult<MarketListingRow>>
Look one Kalshi market up by ticker or by a pasted kalshi.com link.
Paste the link from the post you are checking, or type the ticker — both identify the same contract and resolve to the same single row.
The pasted link is never fetched. It is parsed offline for host and shape, the ticker is extracted from it, and the venue request is built from the resolved API address, so a lookalike host cannot steer a request anywhere.
Both tiers are searched: the live tier answers first, and a market older than
its retention window falls through to the historical tier and comes back
stamped source: "kalshi.historical". A ticker neither tier knows raises
rather than resolving to an empty result — “no such market” and “no data” are
different answers and this verb will not conflate them.
Parameters
Section titled “Parameters”urlOrId
Section titled “urlOrId”string
a Kalshi market ticker ("KXHIGHNY-26MAY29-T85") or a
kalshi.com market link carrying ?ticker=.
Returns
Section titled “Returns”Promise<DataResult<MarketListingRow>>
Throws
Section titled “Throws”urlOrId is not a valid ticker, or is a link that
identifies a series or an event rather than a single market.
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
kalshiMarkets()
Section titled “kalshiMarkets()”kalshiMarkets(
args,opts):Promise<DataResult<MarketListingRow>>
List Kalshi markets, narrowed by series, event, status, or category.
Prices come back as probabilities in [0,1] so a frame from this venue and a
frame from another can be concatenated and compared without a unit conversion
at the call site. The Polymarket-only columns (market_slug,
outcome_token_ids, volume_usd, liquidity_usd) are null: Kalshi serves no
such value, and this frame would rather say nothing than say something
plausible and wrong.
Multivariate event combinations are always excluded. They are a >400,000 row combinatorial universe that no research question asks for, and there is no argument to let them back in.
Parameters
Section titled “Parameters”KalshiMarketsArgs = {}
Returns
Section titled “Returns”Promise<DataResult<MarketListingRow>>
a schema.markets.listing.v1 result, one row per market.
Throws
Section titled “Throws”no filter and no all: true, an invalid status,
or historical: true without series.
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
kalshiOrderbook()
Section titled “kalshiOrderbook()”kalshiOrderbook(
urlOrId,args,opts):Promise<DataResult<MarketOrderbookRow>>
Fetch the current order book for one Kalshi market, in long format.
Kalshi quotes its book as YES bids and NO bids. A resting NO bid at price p
is an offer to sell YES at 1 - p, so the NO side is mapped onto the yes-token
ask by ask_price = 1 - no_bid_price. That identity is what makes a Kalshi book
directly comparable to a Polymarket one; without it the two venues’ books look
like they disagree when they do not.
level is 0-based from the best price on each side (highest bid, lowest ask),
assigned here rather than trusted from the wire, so the ordering is identical
however the venue happened to sort its arrays.
A book is a live concept and there is no /historical book endpoint, so these
rows are always source: "kalshi". captured_at is the client clock — the
venue stamps the snapshot with no time of its own.
Parameters
Section titled “Parameters”urlOrId
Section titled “urlOrId”string
KalshiOrderbookArgs = {}
Returns
Section titled “Returns”Promise<DataResult<MarketOrderbookRow>>
Throws
Section titled “Throws”urlOrId is not a Kalshi market reference, or
depth is outside [1, 1000].
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
kalshiSeries()
Section titled “kalshiSeries()”kalshiSeries(
args,opts):Promise<DataResult<MarketSeriesRow>>
Browse Kalshi’s recurring-contract catalog.
A series is the concept a researcher thinks in — “the NYC daily high family” — and each series owns the events and markets beneath it. Start here, then narrow with kalshiEvents and kalshiMarkets.
This endpoint answers with everything, in one response. Measured July 2026:
12,330 series, 16,277,583 bytes uncompressed / 2.29 MB gzipped, in 0.66 s. It
ignores limit and returns no cursor, so category is the only narrowing that
actually shrinks the payload. Those numbers are what the venue served when they
were taken and can move as the catalog grows.
The caller reaches Kalshi under their own relationship with the venue; this SDK sends no key and stores nothing.
Parameters
Section titled “Parameters”KalshiSeriesArgs = {}
Returns
Section titled “Returns”Promise<DataResult<MarketSeriesRow>>
a schema.markets.series.v1 result, one row per series. A category the
venue knows nothing about resolves to a zero-row result with the same
provenance stamp — never null, never a bare array.
Throws
Section titled “Throws”neither category nor all: true was given.
Remarks
Section titled “Remarks”Node / server only — Kalshi 403s any non-kalshi.com Origin. See
docs/market-data-browser-support.md.
kalshiSeriesRow()
Section titled “kalshiSeriesRow()”kalshiSeriesRow(
raw):MarketSeriesRow
Map one Kalshi series record onto the series column contract.
Parameters
Section titled “Parameters”Record<string, unknown>
Returns
Section titled “Returns”kalshiTrades()
Section titled “kalshiTrades()”kalshiTrades(
urlOrId,args,opts):Promise<DataResult<MarketTradeRow>>
Fetch the executed-trade tape for one Kalshi market over a time window.
volume_usd is null on every row. Kalshi publishes no USD notional for a fill,
and deriving one from a contract count would invent a number the venue never
served.
The live tape is bounded server-side by min_ts / max_ts. The /historical
tape accepts no time bounds (its confirmed parameter set is
ticker / limit / cursor), so on the fallback path the whole tape comes
back and the window is applied here — sending unsupported bounds would be
ignored upstream and read as a narrowing that never happened. The filter runs
on both paths so the verb’s contract does not change with the tier that
answered.
Parameters
Section titled “Parameters”urlOrId
Section titled “urlOrId”string
Returns
Section titled “Returns”Promise<DataResult<MarketTradeRow>>
Throws
Section titled “Throws”either bound is not a valid Date.
Throws
Section titled “Throws”fromTime >= toTime.
Throws
Section titled “Throws”urlOrId is not a Kalshi market reference.
Remarks
Section titled “Remarks”Node / server only — see docs/market-data-browser-support.md.
makeMarketDataResult()
Section titled “makeMarketDataResult()”makeMarketDataResult<
Row>(rows,source,schemaId,retrievedAt,droppedUnplaceable):DataResult<Row>
Wrap market-data rows in the shared DataResult envelope.
source and retrievedAt map onto the provenance vocabulary;
data_version and quality_control do not apply to a market-data frame and
are explicitly null rather than omitted, so the provenance key set is the
same fixed five on every verb in the SDK.
Rows are frozen: a caller that mutates the array it was handed would corrupt a frame whose provenance still claims it came straight off the venue.
Type Parameters
Section titled “Type Parameters”• Row
Parameters
Section titled “Parameters”readonly Row[]
source
Section titled “source”schemaId
Section titled “schemaId”string
retrievedAt
Section titled “retrievedAt”string
droppedUnplaceable
Section titled “droppedUnplaceable”number = 0
how many rows were dropped because the venue served
no usable instant for them. Mirrors the Python frame’s
df.attrs["rows_dropped_unplaceable"], and like it appears only when > 0.
Returns
Section titled “Returns”DataResult<Row>
normalizeKalshiCandle()
Section titled “normalizeKalshiCandle()”normalizeKalshiCandle(
raw,options):NormalizedCandleRow
Normalize one Kalshi candlestick into a canonical candle row.
Trade OHLC, bid OHLC, ask OHLC, volume_contracts and open_interest are all
present on every row: on an illiquid market the bid/ask legs are often the
only signal, so they are never conditional.
Parameters
Section titled “Parameters”Record<string, unknown>
options
Section titled “options”Returns
Section titled “Returns”Throws
Section titled “Throws”tier is not a known Kalshi tier tag.
Throws
Section titled “Throws”raw does not speak tier’s vocabulary.
normalizeKalshiOrderbook()
Section titled “normalizeKalshiOrderbook()”normalizeKalshiOrderbook(
raw,options):MarketOrderbookRow[]
Normalize a Kalshi book snapshot into long-format level rows.
Kalshi quotes its book as YES bids and NO bids. A resting NO bid at price p
is an offer to sell YES at 1 - p, so the NO side is mapped onto the
yes-token ask by the identity ask_price = 1 - no_bid_price. That
transformation is what makes a Kalshi book directly comparable to a Polymarket
book, and it is stated in the schema notes for side.
level is 0-based from the best price on each side (highest bid, lowest ask),
assigned here rather than trusted from the wire, so the ordering is identical
no matter how the venue happened to sort the array.
Parameters
Section titled “Parameters”Record<string, unknown>
options
Section titled “options”Returns
Section titled “Returns”normalizeKalshiTrade()
Section titled “normalizeKalshiTrade()”normalizeKalshiTrade(
raw,options):NormalizedTradeRow
Normalize one Kalshi trade print into a canonical trade row.
price is the YES price: the whole frame speaks probability of YES, and the
printed NO price is always 1 - yes, so carrying it would be a redundant
second unit rather than new information.
volume_usd is null on Kalshi. The venue serves no USD notional for a fill,
and deriving one from a contract count would invent a number the venue never
published.
Parameters
Section titled “Parameters”Record<string, unknown>
options
Section titled “options”Returns
Section titled “Returns”Throws
Section titled “Throws”raw spells its price leg the other tier’s
way. The live tier’s bare yes_price is legacy integer cents, so a
cross-tier read would publish a price scaled by 100.
normalizePolymarketBook()
Section titled “normalizePolymarketBook()”normalizePolymarketBook(
raw,options):MarketOrderbookRow[]
Normalize a Polymarket CLOB book snapshot into long-format level rows.
Unlike Kalshi, Polymarket quotes the token’s own bids and asks directly, so no
side transformation is needed. level is 0-based from the best price on each
side (highest bid, lowest ask), assigned here rather than trusted from the
wire.
The venue stamps its own snapshot timestamp (milliseconds, as a string); it
wins over capturedAt, which is the client-clock fallback used when the venue
omits it.
Parameters
Section titled “Parameters”Record<string, unknown>
options
Section titled “options”Returns
Section titled “Returns”normalizePolymarketPricePoint()
Section titled “normalizePolymarketPricePoint()”normalizePolymarketPricePoint(
raw,options):NormalizedCandleRow
Normalize one Polymarket price tick into a canonical candle row.
The served t is already the bucket start — the opposite of Kalshi, which
serves the period end. Subtracting the interval here would shift every
Polymarket bucket by one slot and put the same trade in adjacent buckets
across venues.
The endpoint serves a last price per bucket, so open, high, low and
close all carry it; there is no bid/ask OHLC and no volume, and those
columns are null rather than fabricated. Polymarket’s native unit is already
probability, so each *_native equals its probability column.
Parameters
Section titled “Parameters”Record<string, unknown>
options
Section titled “options”Returns
Section titled “Returns”normalizePolymarketTrade()
Section titled “normalizePolymarketTrade()”normalizePolymarketTrade(
raw,options):NormalizedTradeRow
Normalize one Polymarket Data-API trade into a canonical trade row.
volume_usd is derived here as size_contracts * price; the venue serves no
USD notional on a trade row. Both inputs are carried on the row so the
derivation is auditable rather than hidden, and it is null whenever either
input is missing — a partially-known notional is not a notional.
side carries the outcome ("yes" / "no" / the multi-outcome label),
matching the Kalshi column. The venue’s own side field is the taker
direction (BUY / SELL), a different axis that the shared trade vocabulary does
not carry.
Parameters
Section titled “Parameters”Record<string, unknown>
options
Section titled “options”Returns
Section titled “Returns”parseKalshiMarketRef()
Section titled “parseKalshiMarketRef()”parseKalshiMarketRef(
urlOrId):string
Return the validated Kalshi market ticker named by urlOrId.
The link is never dereferenced — see parseKalshiRef. The returned
ticker is safe to interpolate into a venue API path: it has been matched
against the fully anchored KALSHI_TICKER_RE allowlist, which admits no /,
?, #, whitespace, or non-ASCII character.
A series- or event-level link throws rather than returning the series slug — a series slug is not a market ticker, and returning one would hand the caller a wrong-but-plausible identifier. Use parseKalshiRef when a non-market link is expected.
Parameters
Section titled “Parameters”urlOrId
Section titled “urlOrId”string
Returns
Section titled “Returns”string
parseKalshiRef()
Section titled “parseKalshiRef()”parseKalshiRef(
urlOrId):KalshiRef
Resolve a Kalshi reference string to a validated, level-tagged identity.
A pasted kalshi.com link is validated for host and path shape and its identifier is pulled out. The link itself is never dereferenced.
A bare identifier (no http prefix) is taken as a market ticker: the caller
asserted “market ref”, and Kalshi’s series / event / market tickers share one
alphabet, so the string alone cannot discriminate them. URLs can be
discriminated by shape, and are — a series or event link comes back tagged as
such with ticker: null rather than having a market ticker invented for it.
Parameters
Section titled “Parameters”urlOrId
Section titled “urlOrId”string
Returns
Section titled “Returns”Throws
Section titled “Throws”the value is not a string, is empty, is non-ASCII, is over-length, or matches neither the ticker allowlist nor a canonical kalshi.com market-link shape.
parsePolymarketEventRef()
Section titled “parsePolymarketEventRef()”parsePolymarketEventRef(
urlOrSlug):string
Return the validated Polymarket event slug named by urlOrSlug.
The link is never dereferenced — see parsePolymarketRef. Accepts an event link, an event+market link (the event slug is taken from the first segment), or a bare slug (taken as an event slug — the caller asserted “event ref”).
A /market/{market-slug} shortlink throws: it carries no event segment, so
there is no event slug to return and inventing one would be the
silent-wrong-identifier failure.
Parameters
Section titled “Parameters”urlOrSlug
Section titled “urlOrSlug”string
Returns
Section titled “Returns”string
parsePolymarketMarketRef()
Section titled “parsePolymarketMarketRef()”parsePolymarketMarketRef(
urlOrSlug):string
Return the validated Polymarket slug named by urlOrSlug.
The link is never dereferenced — see parsePolymarketRef. The returned
slug has been matched against the fully anchored POLYMARKET_SLUG_RE
allowlist and is safe to interpolate into a venue API path.
For /event/{event-slug}/{market-slug} this returns the market slug (the last
segment), not the event slug. For an event-only link it returns the event
slug — an event link genuinely identifies an event, and the level is not
silently hidden: call parsePolymarketRef and read .level when the
caller needs to know which of the two it got.
Parameters
Section titled “Parameters”urlOrSlug
Section titled “urlOrSlug”string
Returns
Section titled “Returns”string
parsePolymarketRef()
Section titled “parsePolymarketRef()”parsePolymarketRef(
urlOrSlug):PolymarketRef
Resolve a Polymarket reference string to a validated, level-tagged identity.
A pasted polymarket.com link is validated for host and path shape and its slug is pulled out. The link itself is never dereferenced.
Level is read from the URL shape: /event/{e}/{m} and /market/{m} are
market-level, /event/{e} is event-level. A bare slug is taken as
market-level — the caller asserted “market ref”, and Polymarket event and
market slugs share one alphabet and cannot be told apart offline.
Parameters
Section titled “Parameters”urlOrSlug
Section titled “urlOrSlug”string
Returns
Section titled “Returns”Throws
Section titled “Throws”the value is not a string, is empty, is non-ASCII, is over-length, or matches neither the slug allowlist nor a canonical polymarket.com market-link shape.
polymarketCandles()
Section titled “polymarketCandles()”polymarketCandles(
urlOrSlug,args,opts):Promise<DataResult<MarketCandleRow>>
Fetch OHLC candles for one Polymarket outcome over a time window.
Paste the link (or type the slug) and name the side; the CLOB token id is resolved internally — see resolveSideToken.
The venue serves no volume on this endpoint. /prices-history answers
{t, p} points and nothing else, so volume_contracts is null on every row —
never 0. A zero would assert “nothing traded in this bucket”, which the venue
never said. open_interest and all eight bid_* / ask_* legs are null for
the same reason: absent is not zero.
The candle is flat. The endpoint serves a last price per bucket, not a true
OHLC, so open === high === low === close within each bucket. That is the
venue’s shape, not a bug in this SDK.
*_native equals the probability column. Polymarket’s native unit is
already probability, so there is no second magnitude to carry — unlike Kalshi,
whose native unit is cents.
Bucket start, and the asymmetry with Kalshi. The CLOB t value is taken as
the bucket start, where Kalshi serves the period end and is shifted back. That
reading is an assumption, not a probed certainty; if it is ever falsified,
every Polymarket bucket shifts by one slot relative to a Kalshi one.
You reach Polymarket under your own relationship with Polymarket. Nothing here is persisted.
Parameters
Section titled “Parameters”urlOrSlug
Section titled “urlOrSlug”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<DataResult<MarketCandleRow>>
Throws
Section titled “Throws”either bound is not a valid Date.
Throws
Section titled “Throws”fromTime >= toTime.
Throws
Section titled “Throws”interval is outside 1m / 1h / 1d.
Throws
Section titled “Throws”urlOrSlug is not a Polymarket reference, or
side is not one of the market’s outcomes.
Remarks
Section titled “Remarks”Browser-direct — CLOB answers Access-Control-Allow-Origin: * plus
Access-Control-Allow-Credentials: true. See
docs/market-data-browser-support.md.
polymarketEventRow()
Section titled “polymarketEventRow()”polymarketEventRow(
raw):MarketEventRow
Map one Gamma event record onto the event column contract.
series_ticker is null, always. The column exists because the other venue has
a series tier; filling it here with the event id or the slug would be inventing
a tier this venue does not have.
Parameters
Section titled “Parameters”Record<string, unknown>
Returns
Section titled “Returns”polymarketEvents()
Section titled “polymarketEvents()”polymarketEvents(
args,opts):Promise<DataResult<MarketEventRow>>
Browse Polymarket events — the top tier of this venue’s hierarchy.
An event groups the markets one question resolves across, and on this venue it
is where a browse starts: there is no series above it. The series_ticker
column is null on every row for exactly that reason — see
polymarketSeries, which says so out loud.
status is not a field Polymarket serves. It is derived from the venue’s own
closed / active / acceptingOrders booleans into the same four words the
other venue uses, so one filter reads across both.
You reach Polymarket under your own relationship with Polymarket. Nothing here is persisted.
Parameters
Section titled “Parameters”PolymarketEventsArgs = {}
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<DataResult<MarketEventRow>>
a schema.markets.events.v1 result, one row per event, with
open_time / close_time as ISO-8601 UTC instants. A query that matches
nothing resolves to a zero-row result with the same provenance stamp — never
null, never a bare array.
Throws
Section titled “Throws”no filter and no all: true, an invalid
status, or an event that is not a recognisable slug or link.
Remarks
Section titled “Remarks”Browser-direct — Gamma answers Access-Control-Allow-Origin: *, so
this runs from a page with no proxy. See docs/market-data-browser-support.md.
polymarketListingRow()
Section titled “polymarketListingRow()”polymarketListingRow(
raw):MarketListingRow
Map one Gamma market record onto the listing column contract.
outcomes and clobTokenIds are two parallel arrays that Gamma serves
JSON-string-encoded and that are positionally aligned. When their lengths
disagree the record cannot be aligned at all, and this builder emits outcomes
with outcome_token_ids null rather than indexing into it. A listing is a
browse: one malformed market should not poison a whole page, and a null says
truthfully that the pairing is unknown. resolveSideToken raises on the
same input, because there an unnoticed misalignment would put a price on the
wrong outcome.
The Kalshi-only columns (series_ticker, volume_contracts, open_interest)
are null rather than filled with a plausible Polymarket substitute: the venue
serves no such value, and absent is not zero.
Parameters
Section titled “Parameters”Record<string, unknown>
Returns
Section titled “Returns”polymarketMarket()
Section titled “polymarketMarket()”polymarketMarket(
urlOrSlug,opts):Promise<DataResult<MarketListingRow>>
Look a Polymarket market up by slug or by a pasted polymarket.com link.
Paste the link from the post you are reading, or type the slug — both identify the same contract and resolve to the same row.
The pasted link is never fetched. It is parsed offline for host and path shape, the slug is pulled out of it, and the venue request is built from the module’s own base address, so a lookalike host cannot steer a request anywhere.
An event-level link resolves to more than one row. Polymarket links come in
two shapes, /event/{event}/{market} and the bare /event/{event}, and the
second one is what people usually have to hand: it is the link the site shows
and the link that gets shared. Refusing it would send the caller back to the
site to find a narrower one, which defeats the point of accepting a link at
all. So an event link resolves the event and returns every market under it, and
this verb’s singular name is a promise about what you ask for, not about how
many rows come back. Read rows.length if that matters, or pass the
market-level link to guarantee one row.
An unknown slug surfaces the venue’s 404 rather than resolving to an empty result. “No such market” and “no data” are different answers and this verb will not conflate them.
Parameters
Section titled “Parameters”urlOrSlug
Section titled “urlOrSlug”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<DataResult<MarketListingRow>>
Throws
Section titled “Throws”urlOrSlug is not a recognised slug or a
canonical polymarket.com link. Thrown before any request exists.
Remarks
Section titled “Remarks”Browser-direct — see docs/market-data-browser-support.md.
polymarketMarkets()
Section titled “polymarketMarkets()”polymarketMarkets(
args,opts):Promise<DataResult<MarketListingRow>>
List Polymarket markets, narrowed by event or status.
Each row carries outcomes and outcome_token_ids as two comma-joined,
positionally aligned lists, which is what a caller needs to pick a side before
asking for a book or a price history. Token ids stay strings: a CLOB token id
is roughly 77 digits, and reading one as a number drops its low-order digits
without raising anything.
When those two arrays disagree in length the record cannot be aligned at all,
and this verb emits outcomes with outcome_token_ids null. The verbs that
resolve a side raise on the same input instead, because there an unnoticed
misalignment would put a price on the wrong outcome.
Prices are probabilities in [0,1] so a frame from this venue and a frame from
the other can be concatenated and compared with no unit conversion at the call
site. volume_usd here is venue-served — Gamma’s own volumeNum, not a figure
computed here — unlike the trade-tape column of the same name, which is derived
as size times price. The Kalshi-only columns (series_ticker,
volume_contracts, open_interest) are null: this venue serves no such value,
and absent is not zero.
You reach Polymarket under your own relationship with Polymarket. Nothing here is persisted.
Parameters
Section titled “Parameters”PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<DataResult<MarketListingRow>>
a schema.markets.listing.v1 result, one row per market.
Throws
Section titled “Throws”no filter and no all: true, an invalid
status, or an event that is not a recognisable slug or link.
Remarks
Section titled “Remarks”Browser-direct — see docs/market-data-browser-support.md.
polymarketOrderbook()
Section titled “polymarketOrderbook()”polymarketOrderbook(
urlOrSlug,args,opts):Promise<DataResult<MarketOrderbookRow>>
Fetch the current order book for one Polymarket outcome, in long format.
Polymarket quotes the token’s own bids and asks directly, so no side transformation is needed — unlike Kalshi, whose NO bids are mapped onto the yes-token ask. Long format is what makes the two comparable: one row per level per side concatenates across venues and keeps the units honest.
level is 0-based from the best price on each side (highest bid, lowest ask),
assigned here rather than trusted from the wire, so the ordering is identical
however the venue happened to sort its arrays.
captured_at comes from the venue’s own millisecond timestamp field, so
every row of one snapshot carries the same instant. When the venue omits it the
client clock stands in.
Parameters
Section titled “Parameters”urlOrSlug
Section titled “urlOrSlug”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<DataResult<MarketOrderbookRow>>
Throws
Section titled “Throws”urlOrSlug is not a Polymarket reference, or
side is not one of the market’s outcomes.
Remarks
Section titled “Remarks”Browser-direct — see docs/market-data-browser-support.md.
polymarketSeries()
Section titled “polymarketSeries()”polymarketSeries(…
_args):never
Always throws: Polymarket has no series tier.
Kalshi groups its recurring contracts into a series above the event, so
kalshiSeries() is where a browse of that venue starts. Polymarket has no such
tier at all — its hierarchy is Event -> Market, and an event is already the
top. Start with polymarketEvents instead.
This verb exists rather than being omitted so the difference is discoverable. A missing export teaches nothing; a shared grammar with a silent hole in it teaches something false.
Every argument is accepted and ignored, so a caller copying a Kalshi call across gets the lesson rather than a complaint about an argument.
Parameters
Section titled “Parameters”…readonly unknown[]
Returns
Section titled “Returns”never
Throws
Section titled “Throws”always. Carries venue, capability and
remedy, and subclasses ContractError, so it is thrown before any I/O and
existing contract handlers still catch it.
polymarketTrades()
Section titled “polymarketTrades()”polymarketTrades(
urlOrSlug,args,opts):Promise<DataResult<MarketTradeRow>>
Fetch the executed-trade tape for one Polymarket market over a time window.
The Data-API market= parameter takes the Gamma conditionId, not a CLOB
token id — the exact reverse of the CLOB price-history parameter of the same
name. Passing a token id returns an empty array rather than an error, which is
a real footgun; this verb resolves the condition id itself so a caller never
meets it.
volume_usd is derived, as size_contracts * price. The venue serves no
USD notional on a trade row: its size is in shares/contracts, and
Polymarket’s own “volume” fields mean three different things depending on which
endpoint you asked. size_contracts is carried alongside so the derivation is
auditable rather than hidden, and volume_usd is null whenever either input is
missing — a partially-known notional is not a notional.
side carries the outcome (yes / no / the multi-outcome label), matching
the Kalshi column. The venue’s own side field is the taker direction
(BUY / SELL), a different axis the shared trade vocabulary does not carry.
The window is half-open, [fromTime, toTime), matching every other windowed
verb in the SDK, and it is applied client-side because the endpoint takes no
time bounds.
Naming a side this market does not offer throws, and it throws before
the tape is requested. “No trades” and “no such outcome” are different
answers: a typo’d side that filtered client-side would resolve to an empty
tape indistinguishable from a quiet window. Naming a side costs the same single
Gamma request as not naming one — see resolveSideToken.
Parameters
Section titled “Parameters”urlOrSlug
Section titled “urlOrSlug”string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<DataResult<MarketTradeRow>>
Throws
Section titled “Throws”either bound is not a valid Date.
Throws
Section titled “Throws”fromTime >= toTime.
Throws
Section titled “Throws”urlOrSlug is not a Polymarket reference, or
side is not one of the market’s outcomes (the message names the ones that
are).
Remarks
Section titled “Remarks”Browser-direct — see docs/market-data-browser-support.md.
probabilityToCents()
Section titled “probabilityToCents()”probabilityToCents(
probability):null|number
Convert a probability in [0,1] to the Kalshi-native cents magnitude.
Kept as a float so sub-cent price tiers survive as fractional cents
(0.567 -> 56.7) instead of being truncated.
Parameters
Section titled “Parameters”probability
Section titled “probability”null | number
Returns
Section titled “Returns”null | number
requireNarrowing()
Section titled “requireNarrowing()”requireNarrowing(
activeFilters,options):void
Refuse an unnarrowed browse, before a socket is opened.
Kalshi’s open universe is 75,603 markets once multivariate event combos are
excluded, and /series answers with all 12,330 series in a single 16.3 MB
response (it ignores limit and returns no cursor, so there is no server-side
way to ask for less). An unnarrowed call is therefore never a small mistake,
and it is not only an ergonomics problem: Kalshi’s data terms bar systematic
retrieval, so sweeping the venue by accident is a licensing exposure the caller
did not choose.
all: true is the deliberate opt-in. It is a word the caller has to type,
which is the point.
An empty or whitespace-only string counts as absent, not as a filter. The
venue treats series: "" as no narrowing at all, so accepting it here would
let the empty string walk straight past this gate and sweep the universe the
gate exists to protect — the one input most likely to arrive from an unfilled
form field.
Parameters
Section titled “Parameters”activeFilters
Section titled “activeFilters”Record<string, unknown>
every narrowing argument the verb accepts, mapped to the value it was called with. The keys define the valid set named in the error, so a new filter can never be added without appearing in the teaching message.
options
Section titled “options”Returns
Section titled “Returns”void
Throws
Section titled “Throws”no filter was supplied and all is false.
requirePolymarketNarrowing()
Section titled “requirePolymarketNarrowing()”requirePolymarketNarrowing(
activeFilters,options):void
Refuse an unnarrowed browse, before a socket is opened.
How big the Polymarket universe actually is has not been measured by this SDK, and the figures in general circulation disagree with each other by orders of magnitude, so no row count appears in the message below. The absence is deliberate: a number the SDK cannot stand behind would read as authority it has not earned. What is true regardless of the count is that an unnarrowed keyset walk pages until the venue stops answering, which is never a small mistake, and that sweeping a venue by accident is a licensing exposure the caller did not choose.
all: true is the deliberate opt-in. It is a word the caller has to type,
which is the point.
An empty or whitespace-only string counts as absent, not as a filter: a blank
event narrows nothing at the venue, so accepting it would let the empty
string walk past the gate and start the sweep it exists to prevent. The rule
matches the Kalshi gate’s; only the message is venue-specific.
Parameters
Section titled “Parameters”activeFilters
Section titled “activeFilters”Record<string, unknown>
every narrowing argument the verb accepts, mapped to the value it was called with. The keys define the valid set named in the error, so a new filter can never be added without appearing in the teaching message.
options
Section titled “options”boolean
string
Returns
Section titled “Returns”void
Throws
Section titled “Throws”no filter was supplied and all is false.
resolveOutcomeToken()
Section titled “resolveOutcomeToken()”resolveOutcomeToken(
outcomes,tokenIds,side):string
Resolve an outcome label to its positionally aligned CLOB token id.
Gamma serves outcomes and clobTokenIds as two parallel arrays. Indexing
blindly is unsafe: Gamma also carries multi-outcome (non-binary) markets, so a
length mismatch means the record cannot be aligned at all and a positional
read would hand back some other outcome’s token.
Parameters
Section titled “Parameters”outcomes
Section titled “outcomes”unknown
tokenIds
Section titled “tokenIds”unknown
string
Returns
Section titled “Returns”string
Throws
Section titled “Throws”the two arrays have different lengths.
Throws
Section titled “Throws”side is not one of the market’s outcomes; the
message names the outcomes that are on offer.
resolveSideToken()
Section titled “resolveSideToken()”resolveSideToken(
slugOrUrl,side,opts):Promise<ResolvedSide>
Resolve a slug (or a pasted market link) plus an outcome side to its CLOB token id, carrying the condition id alongside.
This is the entry contract the price verbs are built on: a caller who has a
link and knows which side they mean never has to learn what a 77-digit
ERC-1155 asset id is. One Gamma /markets/slug/{slug} request answers both.
Both identifiers come back, deliberately. /prices-history and /book take
the token id; the Data-API /trades takes the condition id. Returning one and
letting the caller derive the other is how a request ends up addressing the
wrong thing and getting an empty array instead of an error.
Side matching is case-insensitive. A length mismatch between outcomes and
clobTokenIds raises here, where polymarketListingRow emits an honest
null for the same malformed market: a listing is a browse and one bad row must
not poison a page, but a side-resolving read that guessed would put a price on
the wrong outcome and say nothing.
Parameters
Section titled “Parameters”slugOrUrl
Section titled “slugOrUrl”string
string
PolymarketDataClientOptions = {}
Returns
Section titled “Returns”Promise<ResolvedSide>
Throws
Section titled “Throws”slugOrUrl is not a recognisable reference, or
side is not one of the market’s outcomes (the message names the ones that
are).
Throws
Section titled “Throws”outcomes and clobTokenIds disagree in
length, so the record cannot be aligned at all.
validateEnum()
Section titled “validateEnum()”validateEnum(
value,allowed,field):void
Reject a value outside allowed, suggesting the nearest valid one.
Kalshi validates status server-side and answers HTTP 400 on anything else, so
checking here turns a transport error into a readable one — and it happens
pre-fetch, so a typo costs no request.
Parameters
Section titled “Parameters”undefined | string
allowed
Section titled “allowed”readonly string[]
string
Returns
Section titled “Returns”void
Throws
Section titled “Throws”value is neither undefined nor in allowed.
validateInterval()
Section titled “validateInterval()”validateInterval(
interval,venue):number
Return the bucket length in seconds for interval.
An invalid resolution is a fixable typo, so the error hands back the fix: the
message names the whole valid set rather than only saying no, and supported
carries it structurally so an agent can branch without parsing prose.
Parameters
Section titled “Parameters”interval
Section titled “interval”string
string
Returns
Section titled “Returns”number
Throws
Section titled “Throws”interval is outside MARKET_INTERVALS.
validatePolymarketEnum()
Section titled “validatePolymarketEnum()”validatePolymarketEnum(
value,allowed,field):void
Reject a value outside allowed, suggesting the nearest valid one.
Polymarket serves no status field to validate against, so unlike the Kalshi twin this check is not standing in for a venue HTTP 400 — the vocabulary is entirely ours. That makes checking it here the only place a typo can be caught: an unrecognised status would otherwise silently match no row and return an empty result that looks like a real answer.
Parameters
Section titled “Parameters”undefined | string
allowed
Section titled “allowed”readonly string[]
string
Returns
Section titled “Returns”void
Throws
Section titled “Throws”value is neither undefined nor in allowed.