Kalshi
7 tablesKalshi's prediction-market exchange — binary YES/NO contracts on NBA games (winner, spread, and total markets) from the 2025-26 season onward, with event-driven price candles, the public trade tape, and on-exchange settlement results.
Machine-readable spec: /api/openapi/public.json (OpenAPI 3.1)
Main· 3 tables
series
kalshi.seriesFamilies of related Kalshi binary markets organized around a common theme — all NBA game-winner markets, all NBA spread markets, all NFL totals markets, election markets, weather markets. Tracks series-level metadata and sync state.
▸Fields9
| Field | Type | References | Description |
|---|---|---|---|
| idkey | bigint | — | Primary Key |
| category | string | — | e.g. "Sports > Basketball > NBA" e.g. Sports > Basketball > NBA |
| contract_type | stringnullable | — | "gw", "spread", "ou" Values:gwspreadou |
| fetched_at | timestamptz | — | — e.g. 2026-06-14T18:01:14.930Z |
| frequency | stringnullable | — | "daily", "weekly" e.g. — (all-null in sample) |
| is_active | boolean | — | — e.g. true |
| league_code | stringnullable | — | e.g. "nba", "nfl", null for non-sport e.g. nba |
| series_ticker | string | — | e.g. "KXNBAGAME" Values:KXNBAGAMEKXNBASPREADKXNBATOTAL |
| title | string | — | — Values:NBA Game WinnerNBA SpreadNBA Total |
GET/api/v1/kalshi/seriesList series for Kalshi
Parameters
limitqueryintegeroptionaldefault 50Page size. Defaults to 50; max 200.
from_idquerybigintoptionalReturn rows with id strictly greater than this value; page using the previous response's `next_from_id`. Omit on the first page.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/series?limit=3'Responses
200series rows matching the declared filter set, wrapped in { series, limit, next_from_id }. next_from_id is the last row's id on a full page — pass it back via ?from_id= to walk the full result; null marks the terminal page.application/jsonshow example ▸
400No declared filter set was satisfied — response body matches MissingRequiredFiltersError; pick one combo from the accepted-sets hint and resend.
application/jsonGET/api/v1/kalshi/series/{id}Get a single sery by id
Parameters
idpathbigintrequiredPrimary key (id) of the sery row.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/series/{pk_value}'Responses
200Single sery row.application/jsonshow example ▸
404Row not found.
events
kalshi.eventsA real-world event that anchors a set of Kalshi markets — for sports, a specific game or matchup; for politics, an election or vote; for finance, a price level on a target date. E.g., MEM@POR game-winner event has 2 markets (MEM wins, POR wins).
▸Fields15
| Field | Type | References | Description |
|---|---|---|---|
| idkey | bigint | — | Primary Key |
| competition_id | bigintnullable | — | Polymorphic cross-schema ref — {league}.games (team sports) or golf.tournaments (golf), resolved during sync by league_code. Dereference via main.competitions. NULL until linked. |
| league_game_id | stringnullable | — | NBA CDN game ID for fallback cross-ref e.g. — (all-null in sample) |
| series_id | bigint | — e.g. 1 | |
| away_team | stringnullable | — | Tricode: "MEM" e.g. SAS |
| category | string | — | — e.g. Sports > Basketball > NBA |
| event_ticker | string | — | e.g. "KXNBAGAME-26FEB06MEMPOR" e.g. KXNBAGAME-26FEB12DALLAL |
| fetched_at | timestamptz | — | — e.g. 2026-03-30T01:56:47.997Z |
| game_date | datenullable | — | Game date for sport events e.g. 2026-04-10T04:00:00.000Z |
| home_team | stringnullable | — | Tricode: "POR" e.g. SAS |
| league_code | stringnullable | — | Denormalized for filtering e.g. nba |
| market_count | integernullable | — | — e.g. 11 |
| settled_at | timestamptznullable | — | — e.g. — (all-null in sample) |
| status | string | — | "open", "closed", "settled" e.g. closed |
| title | string | — | — e.g. Toronto wins by over 8.5 Points? |
GET/api/v1/kalshi/eventsList events for Kalshi
Requires one of:
series_id or league_code or competition_id — requests satisfying none of these return 400.Parameters
series_idquerybigintoptionalFilter to events within a single Kalshi series (e.g., one row of `series` ⇒ all KXNBAGAME events).
competition_idquerybigintoptionalFilter to events linked to a specific competition (cross-schema game or golf tournament; resolved during sync via league_code).
league_codequerystringoptionalFilter to all events for a league (e.g. league_code=nba) — the league-level entry point, mirroring polymarket.events.
limitqueryintegeroptionaldefault 50Page size. Defaults to 50; max 200.
from_idquerybigintoptionalReturn rows with id strictly greater than this value; page using the previous response's `next_from_id`. Omit on the first page.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/events?series_id=1'Responses
200events rows matching the declared filter set, wrapped in { events, limit, next_from_id }. next_from_id is the last row's id on a full page — pass it back via ?from_id= to walk the full result; null marks the terminal page.application/jsonshow example ▸
400No declared filter set was satisfied — response body matches MissingRequiredFiltersError; pick one combo from the accepted-sets hint and resend.
application/jsonGET/api/v1/kalshi/events/{id}Get a single event by id
Parameters
idpathbigintrequiredPrimary key (id) of the event row.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/events/{pk_value}'Responses
200Single event row.application/jsonshow example ▸
404Row not found.
markets
kalshi.marketsAn individual binary contract on Kalshi — a YES/NO question with a defined resolution date and rule, priced between 0 and 100 cents. Stores latest known state (overwritten on sync).
▸Fields23
| Field | Type | References | Description |
|---|---|---|---|
| idkey | bigint | — | Primary Key |
| competition_id | bigintnullable | — | Polymorphic cross-schema ref (denormalized from event) — {league}.games or golf.tournaments, by league_code. Dereference via main.competitions. NULL until linked. |
| event_id | bigint | — e.g. 66 | |
| series_id | bigint | Denormalized from event for direct queries e.g. 2 | |
| close_time | timestamptznullable | — | — e.g. 2026-02-27T03:00:00.000Z |
| contract_type | string | — | "gw", "spread", "ou" Values:spreadgwou |
| expiration_time | timestamptznullable | — | — e.g. 2026-02-26T00:30:00.000Z |
| fetched_at | timestamptz | — | — e.g. 2026-02-23T05:31:45.400Z |
| last_price | integernullable | — | Cents (1-99) e.g. 1 |
| line | decimalnullable | — | Spread line for spread markets (e.g., -3.5). UNRELIABLE for ou (totals) markets — mostly null, and populated values hold the playoff series game number, not the total; parse the numeric ticker suffix (e.g. …-238 ⇒ 238) for the O/U line. e.g. 1.5000 |
| liquidity | integer | — | — e.g. 0 |
| open_interest | integer | — | — e.g. 1304 |
| open_time | timestamptznullable | — | — e.g. 2026-02-07T02:07:00.000Z |
| result | stringnullable | — | "yes", "no", "scalar", null if undetermined Values:noyesscalar |
| settled_at | timestamptznullable | — | Settlement timestamp from Kalshi settlement_ts e.g. 2026-01-20T02:37:00.941Z |
| settlement_value | integernullable | — | Settlement payout for YES side in cents (0-100 for binary, 1-99 possible for scalar) e.g. 0 |
| status | string | — | "initialized", "inactive", "active", "closed", "determined", "disputed", "amended", "finalized" e.g. finalized |
| subtitle | stringnullable | — | — e.g. — (all-null in sample) |
| ticker | string | — | e.g. "KXNBAGAME-26FEB06MEMPOR-POR" e.g. KXNBAGAME-26FEB12DALLAL-LAL |
| title | string | — | — e.g. Los Angeles C at Houston: Total Points |
| volume | integer | — | Lifetime volume e.g. 2226 |
| yes_ask | integernullable | — | Cents. 1-99 while an order book exists; 100 when there is no resting ask (the common state on settled markets). e.g. 100 |
| yes_bid | integernullable | — | Cents. 1-99 while an order book exists; 0 when there is no resting bid (the common state on settled markets). e.g. 0 |
GET/api/v1/kalshi/marketsList markets for Kalshi
Requires one of:
event_id or competition_id — requests satisfying none of these return 400.Parameters
event_idquerybigintoptionalFilter to all markets that belong to a single event (e.g., MEM@POR game-winner event ⇒ two markets, MEM wins and POR wins).
series_idquerybigintoptionalFilter to all markets in a single series (denormalized for direct queries).
competition_idquerybigintoptionalFilter to markets linked to a specific competition — all of its markets in one call.
limitqueryintegeroptionaldefault 50Page size. Defaults to 50; max 200.
from_idquerybigintoptionalReturn rows with id strictly greater than this value; page using the previous response's `next_from_id`. Omit on the first page.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/markets?event_id=1'Responses
200markets rows matching the declared filter set, wrapped in { markets, limit, next_from_id }. next_from_id is the last row's id on a full page — pass it back via ?from_id= to walk the full result; null marks the terminal page.application/jsonshow example ▸
400No declared filter set was satisfied — response body matches MissingRequiredFiltersError; pick one combo from the accepted-sets hint and resend.
application/jsonGET/api/v1/kalshi/markets/{id}Get a single market by id
Parameters
idpathbigintrequiredPrimary key (id) of the market row.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/markets/{pk_value}'Responses
200Single market row.application/jsonshow example ▸
404Row not found.
Markets· 4 tables
market_statuses
kalshi.market_statusesThe trading-status period log for each Kalshi market — one row per state change with start/end timestamps, recording when the market was open, closed, settled, etc. Sparse coverage — captured 2025-10 through 2026-02 for ~1,500 markets; not currently updating.
▸Fields6
| Field | Type | References | Description |
|---|---|---|---|
| idkey | bigint | — | Primary Key |
| details | jsonbnullable | — | — |
| end_ts | timestamptz | — | — |
| start_ts | timestamptz | — | — |
| status | string | — | "open", "closed", "settled", etc. e.g. — (all-null in sample) |
| ticker | string | — | — e.g. — (all-null in sample) |
GET/api/v1/kalshi/market_statusesList market_statuses for Kalshi
Requires one of:
market_id — requests satisfying none of these return 400.Parameters
market_idquerybigintoptionalFilter to status periods for a single Kalshi market by numeric id (resolves to ticker via JOIN to kalshi.markets).
limitqueryintegeroptionaldefault 50Page size. Defaults to 50; max 200.
from_idquerybigintoptionalReturn rows with id strictly greater than this value; page using the previous response's `next_from_id`. Omit on the first page.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/market_statuses?market_id=1'Responses
200market_statuses rows matching the declared filter set, wrapped in { market_statuses, limit, next_from_id }. next_from_id is the last row's id on a full page — pass it back via ?from_id= to walk the full result; null marks the terminal page.application/jsonshow example ▸
400No declared filter set was satisfied — response body matches MissingRequiredFiltersError; pick one combo from the accepted-sets hint and resend.
application/jsonGET/api/v1/kalshi/market_statuses/{id}Get a single market_statuse by id
Parameters
idpathbigintrequiredPrimary key (id) of the market_statuse row.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/market_statuses/{pk_value}'Responses
200Single market_statuse row.application/jsonshow example ▸
404Row not found.
candles
kalshi.candlesOHLC candlestick price summaries for Kalshi markets — the open, high, low, and close prices over standard time bins (1 minute, 5 minute, 1 hour, 1 day), with traded volume per bin. Flattened columns (not JSON) for SQL queryability.
▸Fields15
| Field | Type | References | Description |
|---|---|---|---|
| idkey | bigint | — | Primary Key |
| market_id | bigint | — e.g. 8 | |
| end_period_ts | integer | — | Unix timestamp of period end e.g. 1770781714 |
| open_interest | integer | — | OI at period end e.g. 0 |
| period_interval | integer | — | Seconds (1, 60, 3600, 86400) e.g. 1 |
| ticker | string | — | Denormalized Values:KXNBAGAME-26FEB11MEMDEN…KXNBAGAME-26FEB11OKCPHX… |
| volume | integer | — | Period volume e.g. 1 |
| yes_ask_close | integernullable | — | — e.g. 86 |
| yes_ask_high | integernullable | — | — e.g. 86 |
| yes_ask_low | integernullable | — | — e.g. 30 |
| yes_ask_open | integernullable | — | — e.g. 86 |
| yes_bid_close | integernullable | — | — e.g. 86 |
| yes_bid_high | integernullable | — | — e.g. 86 |
| yes_bid_low | integernullable | — | — e.g. 30 |
| yes_bid_open | integernullable | — | Cents e.g. 86 |
GET/api/v1/kalshi/candlesList candles for Kalshi
Requires one of:
market_id — requests satisfying none of these return 400.Parameters
market_idquerybigintoptionalFilter to candles for a single Kalshi market.
period_intervalqueryintegeroptionalBin width in seconds. Currently every row is period_interval=1 (event-driven captures at up-to-1s resolution, irregular spacing) — resample client-side for fixed OHLC bins.
limitqueryintegeroptionaldefault 50Page size. Defaults to 50; max 200.
from_idquerybigintoptionalReturn rows with id strictly greater than this value; page using the previous response's `next_from_id`. Omit on the first page.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/candles?market_id=1'Responses
200candles rows matching the declared filter set, wrapped in { candles, limit, next_from_id }. next_from_id is the last row's id on a full page — pass it back via ?from_id= to walk the full result; null marks the terminal page.application/jsonshow example ▸
400No declared filter set was satisfied — response body matches MissingRequiredFiltersError; pick one combo from the accepted-sets hint and resend.
application/jsonGET/api/v1/kalshi/candles/{id}Get a single candle by id
Parameters
idpathbigintrequiredPrimary key (id) of the candle row.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/candles/{pk_value}'Responses
200Single candle row.application/jsonshow example ▸
404Row not found.
market_snapshots
kalshi.market_snapshotsTime-series price captures for Kalshi markets — the YES bid/ask and NO bid/ask, last trade price, and order-book depth recorded as prices move throughout the trading session. Same pattern as nba.game_line.
▸Fields11
| Field | Type | References | Description |
|---|---|---|---|
| idkey | bigint | — | Primary Key |
| market_id | bigint | — e.g. — (all-null in sample) | |
| captured_at | timestamptz | — | — e.g. — (all-null in sample) |
| is_opening | boolean | — | First snapshot for this market e.g. — (all-null in sample) |
| last_price | integernullable | — | — e.g. — (all-null in sample) |
| liquidity | integer | — | — e.g. — (all-null in sample) |
| open_interest | integer | — | — e.g. — (all-null in sample) |
| ticker | string | — | Denormalized for efficient queries e.g. — (all-null in sample) |
| volume | integer | — | Cumulative at capture time e.g. — (all-null in sample) |
| yes_ask | integernullable | — | — e.g. — (all-null in sample) |
| yes_bid | integernullable | — | — e.g. — (all-null in sample) |
⚠️ This endpoint is documented but not yet live. Calls return
503 until data is wired in.GET/api/v1/kalshi/market_snapshotsList market_snapshots for Kalshi
Requires one of:
market_id — requests satisfying none of these return 400.Parameters
market_idquerybigintoptionalFilter to snapshots for a single Kalshi market.
limitqueryintegeroptionaldefault 50Page size. Defaults to 50; max 200.
from_idquerybigintoptionalReturn rows with id strictly greater than this value; page using the previous response's `next_from_id`. Omit on the first page.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/market_snapshots?market_id=1'Responses
200market_snapshots rows matching the declared filter set, wrapped in { market_snapshots, limit, next_from_id }. next_from_id is the last row's id on a full page — pass it back via ?from_id= to walk the full result; null marks the terminal page.application/jsonshow example ▸
400No declared filter set was satisfied — response body matches MissingRequiredFiltersError; pick one combo from the accepted-sets hint and resend.
application/json503Coming soon — handler returns 503 until data is wired in.
GET/api/v1/kalshi/market_snapshots/{id}Get a single market_snapshot by id
Parameters
idpathbigintrequiredPrimary key (id) of the market_snapshot row.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/market_snapshots/{pk_value}'Responses
200Single market_snapshot row.application/jsonshow example ▸
404Row not found.
503Coming soon — handler returns 503 until data is wired in.
public_trades
kalshi.public_tradesEvery executed trade on Kalshi — price, size, side (YES or NO), and timestamp, comprising the public market tape. Represents completed market trades across all users.
▸Fields14
| Field | Type | References | Description |
|---|---|---|---|
| idkey | bigint | — | Primary Key |
| market_id | bigint | — e.g. 900 | |
| trade_id | string | — | — e.g. befe59d2-106d-6057-517e-eeddd083eba6 |
| count | integer | — | — e.g. 1 |
| count_fp | stringnullable | — | — e.g. 1.00 |
| created_time | timestamptznullable | — | — e.g. 2026-02-13T05:23:27.794Z |
| no_price | integernullable | — | — e.g. 1 |
| no_price_dollars | stringnullable | — | — e.g. 0.0100 |
| price | floatnullable | — | — e.g. 0.99 |
| raw_payload | jsonb | — | — e.g. {"count":18,"count_fp":"18.00","created_time":"2026-02-13T0… |
| taker_side | stringnullable | — | "yes" | "no" Values:noyes |
| ticker | string | — | — e.g. KXNBATOTAL-26FEB12DALLAL-229 |
| yes_price | integernullable | — | — e.g. 99 |
| yes_price_dollars | stringnullable | — | — e.g. 0.9900 |
GET/api/v1/kalshi/public_tradesList public_trades for Kalshi
Requires one of:
market_id — requests satisfying none of these return 400.Parameters
market_idquerybigintoptionalFilter to trades on a single Kalshi market.
limitqueryintegeroptionaldefault 50Page size. Defaults to 50; max 200.
from_idquerybigintoptionalReturn rows with id strictly greater than this value; page using the previous response's `next_from_id`. Omit on the first page.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/public_trades?market_id=1'Responses
200public_trades rows matching the declared filter set, wrapped in { public_trades, limit, next_from_id }. next_from_id is the last row's id on a full page — pass it back via ?from_id= to walk the full result; null marks the terminal page.application/jsonshow example ▸
400No declared filter set was satisfied — response body matches MissingRequiredFiltersError; pick one combo from the accepted-sets hint and resend.
application/jsonGET/api/v1/kalshi/public_trades/{id}Get a single public_trade by id
Parameters
idpathbigintrequiredPrimary key (id) of the public_trade row.
Restores the documented defaults (trial keys only accept the unchanged defaults).
Request
curl -sS \
-H 'Authorization: Bearer YOUR_API_KEY' \
'https://api.stat-api.com/api/v1/kalshi/public_trades/{pk_value}'Responses
200Single public_trade row.application/jsonshow example ▸
404Row not found.