Kalshi publishes its market data through a free REST API and lets you trade programmatically with signed API keys. Reading events, markets, order books and trades needs no account; placing orders needs a funded Kalshi account and an API key. This guide maps out the API, shows working requests and explains authentication, based on Kalshi’s documentation and API spec as of October 2026.
The API at a glance
| Service | URL | Auth |
|---|---|---|
| REST API (production) | https://external-api.kalshi.com/trade-api/v2 |
Reads: none · trading: signed key |
| REST API (older host, still supported) | https://api.elections.kalshi.com/trade-api/v2 |
Same as above |
| REST API (demo) | https://external-api.demo.kalshi.co/trade-api/v2 |
Separate demo account and keys |
| WebSocket (production) | wss://external-api-ws.kalshi.com/trade-api/ws/v2 |
Signed handshake required |
| WebSocket (demo) | wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2 |
Signed handshake required |
| FIX | FIXT.1.1 / FIX 5.0 SP2 over TLS | On request, for institutional users |
Despite the name, the “elections” host serves every Kalshi market, not just political ones. Demo and production keys are separate and don’t work on each other’s servers.
How Kalshi data is organised
- Series: a recurring question, such as the daily high temperature in New York (
KXHIGHNY). - Event: one instance of it, such as a particular day (
KXHIGHNY-26OCT28). - Market: one yes/no contract within the event, such as a single temperature band (
KXHIGHNY-26OCT28-T67).
Prices are fixed-point dollar strings with up to four decimals, such as "0.5600", in fields ending in _dollars. Contract counts are strings with two decimals in fields ending in _fp, such as volume_fp and open_interest_fp. Kalshi removed the older integer-cent fields (yes_bid, last_price and so on) in early 2026, so code written against them needs updating.
Reading markets (no account needed)
Open events in a series, with their markets included:
curl "https://external-api.kalshi.com/trade-api/v2/events?series_ticker=KXHIGHNY&status=open&with_nested_markets=true"
A single market, with its rules and current prices:
curl "https://external-api.kalshi.com/trade-api/v2/markets/KXHIGHNY-26OCT28-T67"
Useful market fields include yes_bid_dollars, yes_ask_dollars, last_price_dollars, volume_24h_fp, open_interest_fp, close_time, status, result, and rules_primary / rules_secondary, which hold the settlement rules in plain English.
| Endpoint | What it returns |
|---|---|
GET /exchange/status |
Whether the exchange and trading are active |
GET /series/{series_ticker} |
Series details, including fee type and settlement sources |
GET /events |
Events; filter by status, series_ticker; up to 200 per page |
GET /events/{event_ticker} |
One event and its markets |
GET /markets |
Markets; filter by event_ticker, series_ticker, status, tickers; up to 1,000 per page |
GET /markets/{ticker}/orderbook |
Resting bids on each side, with optional depth |
GET /markets/trades |
Recent trades, filterable by ticker and time |
GET /series/{series}/markets/{ticker}/candlesticks |
Price history at 1-minute, 1-hour or 1-day intervals |
Lists are paginated with a cursor: pass the returned cursor back to get the next page, and stop when it comes back empty. Combo (multivariate) events are left out of /events and have their own endpoint, /events/multivariate.
Two details that catch people out. The order book lists bids only: a Yes bid at 40¢ is the same as a No offer at 60¢, so you derive asks from the other side. And the status values you filter by (open, closed, settled) differ from the ones returned (active, closed, determined, finalized and others).
Authentication: API keys and signed requests
- Create a key in your Kalshi account’s profile settings, under API Keys. You get a key ID, and the private key downloads once as a PEM file. Kalshi now recommends Ed25519 keys; RSA keys signed with RSA-PSS (SHA-256) are still supported for older clients.
- Sign each request. Build the string
timestamp + METHOD + path, where the timestamp is in milliseconds and the path includes/trade-api/v2but not the query string, for example1703123456789GET/trade-api/v2/portfolio/balance. Sign it with your private key and base64-encode the signature. - Send three headers:
KALSHI-ACCESS-KEY(your key ID),KALSHI-ACCESS-TIMESTAMPandKALSHI-ACCESS-SIGNATURE.
Unlike Polymarket, there’s no wallet and no on-chain signing: a Kalshi key is tied to your verified account, and trades settle in dollars.
Trading endpoints
| Endpoint | Use |
|---|---|
GET /portfolio/balance |
Cash balance and portfolio value |
GET /portfolio/positions |
Open (unsettled) positions; settled ones are under /portfolio/settlements |
GET /portfolio/fills |
Your executed trades |
POST /portfolio/events/orders |
Place an order |
DELETE /portfolio/events/orders/{order_id} |
Cancel an order (amend and decrease endpoints also exist) |
An order needs a ticker, a side (bid or ask), a count and a price as strings, a time_in_force (good_till_canceled, immediate_or_cancel or fill_or_kill) and a self-trade prevention setting. Every order is a limit order: Kalshi removed market-type orders from the API in 2026. The older POST /portfolio/orders endpoint was deprecated in June 2026 in favour of these, so new code should use the /portfolio/events/orders family.
WebSocket streams
Connect to the WebSocket URL with the same three signed headers, signing timestamp + "GET" + "/trade-api/ws/v2". The handshake must be signed even if you only want public data. Then subscribe:
{"id": 1, "cmd": "subscribe", "params": {"channels": ["orderbook_delta", "ticker"], "market_tickers": ["KXHIGHNY-26OCT28-T67"]}}
Market channels include orderbook_delta (a snapshot, then changes), ticker, trade and market_lifecycle_v2. Account channels include fill, user_orders and market_positions.
Rate limits and SDKs
- Rate limits are budgets of tokens per second, and most requests cost 10 tokens. New accounts start on the Basic tier (200 read, 100 write); higher tiers come with an upgrade request or trading volume. Over the limit you get HTTP 429.
GET /account/limitsshows your current limits. - Official SDKs: Python (
kalshi_python_syncandkalshi_python_asyncon PyPI) and TypeScript (kalshi-typescripton npm). The olderkalshi-pythonpackage is deprecated. - Historical data before Kalshi’s cutoff date is served from separate
/historical/endpoints.
Kalshi API vs Polymarket API
| Kalshi | Polymarket | |
|---|---|---|
| Public market data | One REST API, no key | Gamma, CLOB and Data APIs, no key |
| Trading auth | Ed25519 or RSA key, signed headers | Wallet signature (EIP-712) plus HMAC API credentials |
| Money | US dollars in a regulated account | pUSD on Polygon, backed 1:1 by USDC (main exchange) |
| Order book | Bids on each side; asks derived from the other side | Bids and asks per outcome token |
See our Polymarket API guide for the other side. Prediction Tape’s live boards are built on both public APIs.
FAQ
Is the Kalshi API free?
Do I need an API key to get Kalshi prices?
Can I build a Kalshi trading bot?
Why do prices come back as strings?
Related: Prediction market APIs compared · Polymarket API guide · Kalshi glossary · Kalshi review