Kalshi Historical Data (2026)

The Short Answer
Anything older than Kalshi's live window sits behind a separate /historical/ namespace: markets, public trades, candlesticks, plus account-scoped fills, orders and positions. The boundary advances over time, so call GET /historical/cutoff first on every run and route each query by comparing your target date to the right field. History reached back to late June 2021 in our testing, and Kalshi publishes no bulk download. The docs target a three-month live window; on 9 August 2026 the cutoff sat two months back.
If you have ever pulled a market list from Kalshi's API, fetched candles for every ticker, and watched all of those requests return 200, you may think you hold the archive. You hold roughly a thirtieth of it. Kalshi historical data moved behind its own namespace during the first half of 2026, and the endpoints most tutorials point at hold only the trailing couple of months.
This page covers history only: where it lives, how deep it runs, and the failure mode that quietly poisons backtests. For the wider API surface see our Kalshi API guide; for code, the Python tutorial.
Every endpoint behaviour below was checked against Kalshi's own documentation in August 2026. The API is actively changing, so re-check the linked pages before you rely on any figure here.
Key Takeaways
- Two namespaces, not one, and the line between them advances. Read
GET /historical/cutoffevery run; never hardcode a date. - Missing history does not announce itself: one old ticker 404s, but enumerating markets returns a clean 200 with a universe that stops at the cutoff.
- The tiers use different keys for the same numbers:
price.close_dollarslive,price.closehistorical.
The Live and Historical Split, and When It Landed
Kalshi partitioned the API in stages through 2026 and never published a ship date for the first wave. Its changelog only begins on 23 February 2026, and the earliest entry it carries for the new namespace is GET /historical/trades on 6 March 2026. The endpoints the rest of this page leans on, /historical/cutoff and /historical/markets along with the candlestick, fills and orders variants, are never announced there at all, which puts them at or before that start date. Positions came much later, on 23 July 2026. Partitioning now covers markets, candlesticks, trades, orders and positions; events and series are exempt.
The practical consequence is that any Kalshi data tutorial written before 2026 is structurally wrong, because it tells you to pull all of history from GET /markets.
How long does the live tier hold things? The docs give a target window of three months and call the cutoffs "regularly updated, advancing forward over time". That is a target, not a retention promise, and reality has been tighter: on 9 August 2026 the cutoff read 2026-06-09T00:00:00Z, exactly two calendar months back. Kalshi does not explain the gap, so read the endpoint rather than trusting either number.
What Kalshi Historical Data Actually Covers
The mapping is mechanical: every live endpoint has an archived twin under the /historical/ prefix, with the same cursor pagination. The base host is https://external-api.kalshi.com/trade-api/v2, and api.elections.kalshi.com also works; legacy trading-api.kalshi.com now answers 401, a quick way to spot a stale tutorial.
| Data | Live endpoint | Historical endpoint | Auth |
|---|---|---|---|
| Boundary | n/a | /historical/cutoff | None |
| Market list | /markets | /historical/markets | None |
| One market | /markets/{t} | /historical/markets/{t} | None |
| Candles | /series/{s}/markets/{t}/candlesticks | /historical/markets/{t}/candlesticks | None |
| Public trades | /markets/trades | /historical/trades | None |
| Your fills | /portfolio/fills | /historical/fills | API key |
| Your orders | /portfolio/orders | /historical/orders | API key |
| Your positions | /portfolio/positions | /historical/positions | API key |
The cutoff endpoint is the keystone. It returns four fields: market_settled_ts, trades_created_ts, orders_updated_ts and market_positions_last_updated_ts. All four matched when we looked, but Kalshi models them separately, so do not collapse them into one constant. They arrive as RFC3339 strings while every timestamp you send is a Unix integer. Positions archive per whole event, and resting orders are never archived at all.
Kalshi Candlestick History: Intervals, Caps, and a Naming Trap
The live single-market candlestick path needs a series_ticker segment and the historical one does not, so it is a different shape, not just a different prefix. Both require start_ts, end_ts and period_interval, in Unix seconds. The interval enum is exactly 1 (minute), 60 (hour) and 1440 (day); 5 or 15 returns a validation failure, so there is no five-minute candle on Kalshi. The live path also offers include_latest_before_start for continuity at a window's left edge; the historical path does not.
Assembled, a historical call is one line. Substitute a ticker from your own /historical/markets pull and a window of your own:
curl "https://external-api.kalshi.com/trade-api/v2/historical/markets/TICKER/candlesticks?start_ts=1625011200&end_ts=1625097600&period_interval=60"
Each candle comes back in the shape below, with the key names and value formats Kalshi's own schema documents. It is the answer to the naming question further down:
{"candlesticks": [{
"end_period_ts": <unix seconds>,
"price": {"open": "0.5600", "high": ..., "low": ..., "close": ..., "mean": ..., "previous": ...},
"yes_bid": {"open": ..., "high": ..., "low": ..., "close": ...},
"yes_ask": {"open": ..., "high": ..., "low": ..., "close": ...},
"volume": "10.00",
"open_interest": "10.00"
}]}
Volume limits bite fast. Kalshi documents no per-request candlestick maximum for either single-market endpoint; in our testing in August 2026 a request capped out at 5,000 candles and returned a 400 reading "requested time range with candlesticks: 11520.000000, max candlesticks: 5000". Chunk your windows to stay under that ceiling and it works out at roughly 3 days per call at period_interval=1, 200 days at 60, and about 13 years at 1440. The only cap Kalshi publishes sits on the live batch endpoint, which accepts up to 100 tickers and returns up to 10,000 candlesticks across all of them, and that endpoint has no historical twin. Request count is what makes a multi-year backfill slow, not parsing.
Then the trap that costs an afternoon: both paths return the same values under different key names. Live candles use open_interest_fp, volume_fp and price.close_dollars; historical candles use open_interest, volume and price.close. The units and types are identical on both sides. Prices are fixed-point dollar strings, so live price.close_dollars and historical price.close both read "0.5600", and counts are fixed-point strings like "10.00" either way. The _fp suffix stands for fixed point and is live-side vocabulary left over from the March 2026 removal of integer-cent fields; it does not signal a different unit. So your normaliser is a key rename and not a unit conversion, but write it as an explicit map rather than a fallback chain, because a parser keyed on close_dollars against a historical payload yields nulls rather than errors. Kalshi's changelog documents the wider fixed-point migration in detail but never flags this live-versus-historical divergence.
Each candle carries three separate OHLC blocks rather than one. price tracks executed trades, while yes_bid and yes_ask track the resting book, each with its own open, high, low and close for the interval. You get the high and low of the bid and the ask inside every period, not a single mid, which is what lets you model spread and slippage in a backtest instead of assuming you filled at the last trade.
Kalshi Past Market Data: How Deep the Archive Runs
Kalshi publishes no depth figure, so we probed it. Bisecting by day against GET /historical/trades, the earliest trade we could surface was on 30 June 2021, and every probe before that returned an empty array. That reads like the floor of the exchange's own record rather than an API restriction. Historical candlesticks reach the same era with full OHLC and bid/ask blocks, so candles are not shallower than trades.
History therefore runs about 61 months while the live tier holds about two, which leaves a live-only backtester training on roughly three percent of what exists. Those figures are our observations, not a guarantee, and no published policy commits Kalshi to keeping 2021 data forever. If depth matters to your strategy, re-run the bisection yourself.
Kalshi Backtest Data and the Failure That Never Throws
The misconception is that the API is one uniform archive, and that missing data would surface as an error. Only the first half is wrong. Ask for a single 2021 market on a live path and you get a clean 404. Enumerate instead, through GET /markets or GET /events?with_nested_markets=true, and you get HTTP 200 with a universe that just stops at the cutoff: no error, no warning, no flag. The corruption path runs from there: build your list from the live endpoint, pull candles for each ticker, watch every call succeed, and train on two months believing you covered five years. Discovery is where the data goes missing, not the candle fetch.
The fix has four steps. Call /historical/cutoff at the start of every run and route by comparing your target time to the relevant field. Then build the universe from both tiers and union them, because neither list alone is complete: /historical/markets serves settled markets older than the cutoff and stops coming forward, while /markets stops at the same line going back. Enumerate each, dedupe on ticker, and you have the real universe. Merge tiers where a query window straddles the boundary, which is what Kalshi's docs recommend for a complete fill history too. And dedupe on ticker plus candle end timestamp, because in testing a market that closed just before the cutoff returned identical candles from both paths. That overlap looks like archival lag rather than a designed guarantee.
One constraint bites during that enumeration. /historical/markets takes tickers, event_ticker and series_ticker as filters, and the docs state the filters are mutually exclusive, so you cannot combine them in a single request. When you need to slice on more than one dimension, send the narrowest filter you have and apply the rest client-side after paging.
Your outcome labels come from the same pull. The market object carries result, settlement_value_dollars and settlement_ts, so the ground truth your backtest scores against arrives with the universe rather than from a separate settlement call. Markets that have closed but not yet settled come back with an empty result; exclude them from scoring rather than treating the blank as a "no", which is the quiet way to bias a win rate upward.
Be clear-eyed about your fill model, though. Kalshi documents no historical order book endpoint, so there are no depth snapshots to replay. The yes_bid and yes_ask OHLC blocks on the candle are the only book data you get, and they carry price without size. You can model the spread you would have crossed; you cannot model how much you would have filled at it. Size any strategy that assumes meaningful depth accordingly. Feeding a live strategy rather than a notebook? Our Kalshi trading bot guide covers execution.
There Is No Bulk Export
We grepped Kalshi's documentation index for every word a data engineer hopes to find: bulk, export, download, csv, parquet, dump, dataset. The only hit is a pagination page mentioning large datasets in passing. There is no S3 bucket and no data licence page. The only mechanism for volume is cursor pagination, with limit defaulting to 100 and capping at 1000.
That limit and cursor pattern governs the list endpoints, markets and trades. Candlesticks do not paginate at all. You window them instead, chunking start_ts and end_ts so each request stays under the candle ceiling, which is why the two numbers on this page do not contradict each other: 1000 is a page size for lists, 5,000 is a per-request candle count.
Throughput is the open question. Kalshi runs a token bucket with separate read and write budgets, and at the time of writing a 429 carries neither a Retry-After nor any X-RateLimit header, so exponential backoff is the remedy. Treat that as provisional rather than permanent: Kalshi's own wording is that these are "not currently" included, and rate limiting has been one of the more actively revised corners of the API. Re-check that page before you ship a backoff layer.
The rate limit page describes costs for authenticated requests and says nothing about ceilings for public ones, and the historical reads are public, so we will not publish a markets-per-hour figure we cannot verify. There is a way to buy certainty, though: sign your historical reads even though they do not require it, and the published per-tier budgets apply. The entry tier refills 200 read tokens per second and most requests cost 10, so you can size a job against a documented number instead of guessing. Unauthenticated, assume nothing, back off on every 429, and instrument the run so you can raise the rate on evidence. Absorbing this plumbing is why services like Predictefy exist.
Frequently Asked Questions
What is the Kalshi historical data API?
It is not a separate product, just a separate path prefix on the same host. Endpoints under /historical/ serve markets, single markets, candlesticks and public trades without authentication, plus fills, orders and positions for your own account with an API key. GET /historical/cutoff tells you where the line between live and archived data currently sits.
How far back does Kalshi past market data go?
Kalshi publishes no depth figure. In our own probing in August 2026, trades and candlesticks were both available from late June 2021, and every request before that came back empty. We found that boundary by bisecting day by day against /historical/trades until the array stopped coming back empty, so re-run that check yourself if depth matters to your strategy: nothing commits Kalshi to keeping the 2021 data available.
How do I pull Kalshi candlestick history?
Call GET /historical/markets/{ticker}/candlesticks with start_ts, end_ts and period_interval, all three required, timestamps in Unix seconds. The only intervals are 1, 60 and 1440 minutes. Kalshi documents no per-request candlestick maximum, but in our testing a request capped out at 5,000 candles and returned a 400 beyond that, so chunk your windows. There is no batch version of the historical endpoint, so bulk pulls run one request per market.
Does Kalshi historical data require an API key?
The market-facing endpoints do not. Cutoff, markets, single markets, candlesticks and public trades all answered unauthenticated in testing. Fills, orders and positions are scoped to your account and need signed headers. Kalshi documents token costs for authenticated requests and says nothing about ceilings for public ones, so size a bulk pull conservatively.
What does a Kalshi backtest need that a simple data pull misses?
Fetch the cutoff every run, then build your universe from /historical/markets in addition to /markets and dedupe on ticker, because neither list alone is complete. Route each query to the tier its timestamp belongs to, and merge. Normalise field names, because historical candles return open_interest and price.close where live candles return open_interest_fp and price.close_dollars, the same values and units under different keys. Dedupe on ticker plus candle end timestamp too: in testing, some markets near the boundary appeared in both tiers. Your outcome labels come from the market object's result and settlement_ts fields, and there is no historical order book, so bid and ask OHLC is the only fill model available.
Conclusion
Kalshi's archive is genuinely good: five years deep, free, with bid/ask OHLC alongside traded prices. It is just not where older tutorials say it is, and the endpoints holding the recent slice never tell you what they left out. For how these pipes fit the wider data landscape, see our overview of prediction market data. None of this is financial advice, and an API key trades real money on a real exchange.