Updated September 2026 · API v2

Kalshi API v2 Endpoint Reference

If you landed here after pasting external-api.kalshi.com/trade-api/v2/markets?status=open&limit=1000into Google because the response had no bids, you are in the right place. That host is the wrong one for market data. Below is the corrected endpoint map, the v2 field renames, and the auth details that are easy to get wrong.

The short answer

external-api.kalshi.com is the trading host, not the market data host.Its /markets endpoint mostly returns multivariate combo markets with zero bid depth. For market data with live bids, use api.elections.kalshi.com.

Returns empty bidshttps://external-api.kalshi.com/trade-api/v2/markets?status=open&limit=1000
Returns real marketshttps://api.elections.kalshi.com/trade-api/v2/events?status=open&with_nested_markets=true&limit=50

Base URLs: which host for which job

PurposeBase URLAuth required
Market data (events, markets, order books, series)https://api.elections.kalshi.com/trade-api/v2No
Trading and portfolio (balance, orders, positions, settlements)https://external-api.kalshi.com/trade-api/v2Yes (RSA-PSS)

The elections hostname is a historical artifact. It serves every category: weather, crypto, economics, sports and politics. Do not read it as election-only.

Market discovery that actually works

The plain /markets listing is a poor discovery tool. Use the events endpoint with nested markets, which returns roughly 250 or more markets across 50 events, and in our testing about 85 percent of those carried real bid depth.

GET https://api.elections.kalshi.com/trade-api/v2/events
    ?status=open
    &with_nested_markets=true
    &limit=50

If you must use /markets, add mve_filter=exclude to strip multivariate events. Expect a narrower and more obscure result set than the events route.

Field renames: v1 to v2

A large share of broken integrations are simply reading v1 field names that no longer exist. Prices moved to dollar strings, sizes moved to fixed point numbers.

v1 field (gone)v2 fieldTypeExample
yes_bidyes_bid_dollarsstring"0.3300"
yes_askyes_ask_dollarsstring"0.3400"
no_bidno_bid_dollarsstring"0.6600"
no_askno_ask_dollarsstring"0.6700"
last_pricelast_price_dollarsstring"0.3300"
volumevolume_fpnumber785807.77
open_interestopen_interest_fpnumber246292.19
yes_bid_size_fpnumber2574.02
yes_ask_size_fpnumber269.02

All _dollars values are strings. "0.3300" means 33 cents. Cast to float before doing arithmetic, or you will silently concatenate strings.

Authentication: RSA-PSS signing

The signature covers the full path including the /trade-api/v2 prefix. Signing only the short path is the most common auth failure.

# Sign the FULL path, including /trade-api/v2
path_clean = f"/trade-api/v2{endpoint.split('?')[0]}"
message = f"{timestamp_ms}{method}{path_clean}".encode()
signature = private_key.sign(message, PSS(...), SHA256())

Required headers:

KALSHI-CLIENT-KEY-ID is the old header format and will not authenticate against v2.

Placing orders on v2

The v1 order path returns 410 deprecated_v1_order_endpoint. Use the events order path.

POST https://external-api.kalshi.com/trade-api/v2/portfolio/events/orders

{
  "ticker": "KXBTC15M-26JUL231315-15",
  "side": "bid",
  "count": "1",
  "price": "0.3300",
  "time_in_force": "good_till_canceled",
  "self_trade_prevention_type": "taker_at_cross",
  "client_order_id": "edgeoutcome-1234567890"
}

The response is flat, not wrapped in an order object. Read order_id,status, filled_count and remaining_count at the top level. Cancellation still works via DELETE /portfolio/orders/{order_id}.

GET /portfolio/balance returns {"balance": 1983} in cents, not dollars. There is no available_balance field.

Six mistakes that cost the most time

  1. Using external-api.kalshi.com for market data. It returns combo markets with no bids.
  2. Signing the path without the /trade-api/v2 prefix. Every authenticated call fails.
  3. Calling the retired /portfolio/orders path and getting a 410.
  4. Reading available_balance instead of balance, and treating cents as dollars.
  5. Expecting integer cents when v2 returns dollar strings such as "0.3300".
  6. Unwrapping the order response under an order key that does not exist.

Frequently asked questions

Why does external-api.kalshi.com/trade-api/v2/markets?status=open&limit=1000 return markets with no bids?

Because external-api.kalshi.com is the trading and portfolio host, not the market data host. Its /markets endpoint mostly returns multivariate combo markets (tickers like KXMVESPORTSMULTIGAMEEXTENDED) which typically show zero bid depth. For real market data with live bids, use https://api.elections.kalshi.com/trade-api/v2 instead. The name says elections for historical reasons, but it serves every market category.

What is the correct Kalshi API base URL for market data?

Use https://api.elections.kalshi.com/trade-api/v2 for market data such as events, markets, order books and series. Use https://external-api.kalshi.com/trade-api/v2 for authenticated trading calls such as balance, orders, positions and settlements. Mixing the two is the single most common integration mistake.

Is the Kalshi API free?

Yes. Public market data endpoints require no authentication and no API key. You only need an API key pair for authenticated endpoints such as placing orders, reading your balance, or listing your positions. Rate limits apply on both.

Why do yes_bid and no_bid return undefined in API v2?

Those field names belong to v1. In v2 the price fields are suffixed with _dollars and returned as strings, for example yes_bid_dollars with the value "0.3300" meaning 33 cents. Volume and open interest use the _fp suffix and are returned as numbers, for example volume_fp and open_interest_fp.

Why does POST /trade-api/v2/portfolio/orders return 410 deprecated_v1_order_endpoint?

The v1 order path is retired. Place orders against POST /trade-api/v2/portfolio/events/orders instead. The v2 request body sends count and price as strings, and the response is flat rather than nested under an order key.

How do I find open Kalshi markets reliably?

Call GET /events?status=open&with_nested_markets=true&limit=50 on the api.elections.kalshi.com host. It returns events with their markets already embedded, which avoids a second round trip and yields a much higher share of markets with real bid depth than the plain /markets endpoint.

Skip the integration work

The Kalshi AutoTrader Bot Kit ships a working v2 API client with RSA-PSS signing, correct field mapping, rate limit handling and five strategies. Every pitfall on this page is already handled in the code.

See the Bot Kit — 5 strategies, Python, Docker

Related guides