Data
Bulk downloads
History ships as daily Parquet files. Pick datasets, series, and dates; list the files; fetch the ones you do not have. Four ways to do it, all with the same rules.
1. Python client
kalshieye on PyPI (source on GitHub, MIT licensed).
pip install "kalshieye[pandas]"
export KALSHIEYE_API_KEY=clab_...
from kalshieye import Client, replay_book
kx = Client()
kx.estimate(["book_l2", "trades"], "2026-10-12", "2026-10-18", series=["KXBTC*"])
kx.download(["book_l2", "trades"], "2026-10-12", "2026-10-18", series=["KXBTC*"], dest="data")
df = kx.load("bbo_1m", "2026-10-12", "2026-10-18", series="KXBTC15M") # pandas
snaps = kx.load("book_snap_1s", "2026-10-12", "2026-10-12", tickers=["KXBTC15M-26OCT121545-45"])
# Rebuild the full book from book_l2, event by event
for ts, ticker, bids, asks in replay_book(kx.load("book_l2", "2026-10-12", "2026-10-12", series="KXBTC15M")):
...
kx.bundle("KXBTC15M-26OCT121545") # one zip per event: book, trades, spot, settlement
kx.csv("flat/v1/trades/date=2026-10-12/series=KXBTC15M/trades-KXBTC15M-2026-10-12.parquet")2. Saved request and script
Use Export on a series, event, or market, then open Downloads, pick datasets, and request them. Each request has a Python, bash, and PowerShell script. The script reads KALSHIEYE_API_KEY, keeps the lake layout, checks each sha256, and skips files already on disk, so you can re-run it after new days land. Add market tickers to cut rows to those markets; python script.py --csv also writes a .csv.gz next to each file.
3. S3 access (paid plans)
The file gateway is not switched on yet. Flat files says so and sends you to Downloads until it is. When it is on, create an S3 key there (the same keys also show on API). It works with any S3 tool: the AWS CLI, rclone, DuckDB, boto3. Keys are read-only, see only the datasets on your plan, and stop working within a minute of being revoked. A file counts toward your monthly allowance the first time you read it in a month, the same as a download link. Up to five active keys. Creating a key before the gateway is on returns 503.
aws configure set aws_access_key_id KXE... --profile kalshieye
aws configure set aws_secret_access_key ... --profile kalshieye
aws configure set region auto --profile kalshieye
aws configure set s3.addressing_style path --profile kalshieye
aws s3 sync s3://kalshieye/trades/ ./kalshieye/trades/ --profile kalshieye \
--endpoint-url $KALSHIEYE_S3_ENDPOINT \
--exclude "*" --include "date=2026-10-1*/series=KXBTC*"The bucket is kalshieye. Top-level folders are dataset ids (trades/, bbo_1m/, …) plus _manifest/; below that the layout matches the file paths above. DuckDB reads it directly: read_parquet('s3://kalshieye/trades/**/*.parquet', hive_partitioning=true). The API page shows ready-to-paste snippets with your endpoint and key filled in. Keys are also managed with GET/POST /api/v1/files/keys and DELETE /api/v1/files/keys/{id}.
4. HTTP
BASE=https://kalshieye.com
curl -s "$BASE/api/v1/files?dataset=trades&start_date=2026-10-12&end_date=2026-10-16&series=KXBTC*" \
-H "Authorization: Bearer $KALSHIEYE_API_KEY"
curl -s "$BASE/api/v1/files/links" -X POST \
-H "Authorization: Bearer $KALSHIEYE_API_KEY" -H "Content-Type: application/json" \
-d '{"keys": ["flat/v1/trades/date=2026-10-13/series=KXBTC15M/trades-KXBTC15M-2026-10-13.parquet"]}'GET /api/v1/files pages with cursor (up to 1,000 files a page). Add sign=true to get links in the listing itself, and ticker= (repeat) to pick the files that hold those markets.
BASE=https://kalshieye.com
# CSV.gz of one file, optionally cut to tickers. Answers {"status": "building"} until ready.
curl -s "$BASE/api/v1/files/csv" -X POST -H "Authorization: Bearer $KALSHIEYE_API_KEY" \
-H "Content-Type: application/json" -d '{"key": "flat/v1/trades/...parquet", "tickers": []}'
# Event bundle (zip) and 1-second book replay for a market
curl -s -X POST "$BASE/api/v1/events/KXBTC15M-26OCT121545/bundle" -H "Authorization: Bearer $KALSHIEYE_API_KEY"
curl -s "$BASE/api/v1/markets/KXBTC15M-26OCT121545-45/replay?date=2026-10-12" -H "Authorization: Bearer $KALSHIEYE_API_KEY"Poll the same call every couple of seconds until status is ready; built files are cached, so the second caller gets them at once. A CSV counts the same bytes as its Parquet source; a bundle counts the zip once.
Rules
| Rule | What happens |
|---|---|
| Dataset not on your plan | 402 with code: plan_required and required_tier. |
| Dates older than your plan's history | Listings drop them. A range that is entirely older returns 402 with code: history_limited. |
| Monthly download allowance | A file counts the first time you get a link for it in a calendar month. A request that would pass the allowance returns 402 with code: download_quota; ask for fewer files or upgrade. Listing files and estimates are free. |
| Links | Valid for one hour. Ask again for a fresh one; it does not count twice. |
| Day boundaries | UTC. A day is published after it ends; complete: false marks a day that is still being written. |