Complete guide to the Kalshi prediction market API. Authentication with RSA-PSS, REST endpoints, market data, order placement, Python examples, and how to add AI-powered analysis.
Kalshi is the first CFTC-regulated prediction market exchange in the United States. It launched in 2021 and offers binary event contracts that settle to 1(yes)or0 (no). Traders buy and sell contracts representing the probability of real-world events.Markets cover a wide range of categories:
Category
Example markets
Economics
Fed rate decisions, CPI prints, GDP growth, jobless claims
Politics
Election outcomes, congressional votes, government shutdowns
Crypto
Bitcoin and Ethereum price milestones
Weather
Temperature records, hurricane landfalls
Entertainment
Award shows, box office results, streaming top 10
Sports
NFL, NBA, UFC outcomes
All API documentation lives at trading-api.kalshi.com. The base URL for all API requests is:
https://trading-api.kalshi.com/trade-api/v2
Prices on Kalshi are expressed in cents (integers from 1 to 99), representing the implied probability. A YES price of 62 means the market prices the event at roughly 62% likely.
Every Kalshi market has a ticker that encodes the series and expiration:
KXFED-26MAR19^ ^| └── Expiration: March 19, 2026└── Series prefix: KXFED = Federal Reserve rate decisions
Common series prefixes:
Prefix
Category
KXFED
Federal Reserve rate decisions
KXBTC
Bitcoin price milestones
KXETH
Ethereum price milestones
KXINFLATION
CPI / inflation
KXGDP
GDP growth
KXJOBLESS
Weekly jobless claims
KXNFLMVP
NFL MVP
KXUFC
UFC fight outcomes
KXNETFLIX
Netflix Top 10
KXOSCAR
Academy Awards
A ticker like KXBTC-26MAR14-100000 means: Bitcoin price series, expiring March 14, 2026, with a strike of $100,000.You can list all active series by querying the events endpoint:
Log in to your Kalshi account at kalshi.com, go to Settings > API Keys, and upload the contents of kalshi_public_key.pem. Kalshi gives you back an API Key ID (a UUID).
The signing message is the concatenation of timestamp (as string), the HTTP method (GET, POST, etc.), and the request path (including query string for GET requests).
import timeimport base64import httpxfrom cryptography.hazmat.primitives import hashes, serializationfrom cryptography.hazmat.primitives.asymmetric import padding# Load your private key once at startupwith open("kalshi_private_key.pem", "rb") as f: private_key = serialization.load_pem_private_key(f.read(), password=None)API_KEY_ID = "YOUR_KALSHI_API_KEY_ID"BASE_URL = "https://trading-api.kalshi.com"def kalshi_auth_headers(method: str, path: str) -> dict: """Build signed headers for a Kalshi API request.""" timestamp = str(int(time.time() * 1000)) message = f"{timestamp}{method}{path}".encode() signature = private_key.sign( message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH, ), hashes.SHA256(), ) return { "KALSHI-ACCESS-KEY": API_KEY_ID, "KALSHI-ACCESS-TIMESTAMP": timestamp, "KALSHI-ACCESS-SIGNATURE": base64.b64encode(signature).decode(), "Content-Type": "application/json", }# Example: list open marketspath = "/trade-api/v2/markets"resp = httpx.get( f"{BASE_URL}{path}", headers=kalshi_auth_headers("GET", path), params={"limit": 10, "status": "open"},)print(resp.json())
The signing path must match exactly what you send to the server. For GET requests with query parameters, sign the path without the query string. The params are passed separately.
Kalshi enforces approximately 10 requests per second per API key. The limits are not published precisely, but exceeding them returns a 429 status code. Back off with exponential retry when you see it.
The taker fee is maximized at the midpoint: 0.07 * 0.50 * 0.50 = $0.0175 per contract. It decreases as prices approach 0 or 100.Example fees:
YES price
Taker fee per contract
10 cents
$0.0063
25 cents
$0.0131
50 cents
$0.0175
75 cents
$0.0131
90 cents
$0.0063
Maker orders (limit orders that don’t immediately fill) are free. If you can wait for your price, you pay zero fees. This is a significant advantage for algorithmic traders.
Deposits are made via ACH (free, 3-5 days) or wire (25,same−day).Minimumdepositis1. Withdrawals via ACH are free.
There is no official first-party Python SDK from Kalshi. Here are your options:
Option
Pros
Cons
httpx + custom auth
Full control, async support, no extra dependencies
You manage auth signing yourself
requests + custom auth
Familiar API, synchronous
No async, slightly more verbose
kalshi-python (community)
Pre-built auth, basic REST wrapper
Not always up-to-date, limited features
Most production systems use httpx with a reusable auth helper. Wrap the kalshi_auth_headers() function from the authentication section into a client class that handles signing automatically:
Raw Kalshi data tells you what the market thinks. An intelligence layer tells you what the market might be missing.Here is a complete workflow: pull a market from Kalshi via Rekko’s normalized API, run an AI analysis, and get a trading signal with position sizing.
Rekko normalizes Kalshi data into a consistent format alongside Polymarket and Robinhood. Prices are returned as decimals (0.0 to 1.0) instead of raw cents.
The analysis pipeline researches the market question, synthesizes findings from multiple sources, and produces an independent probability estimate. It runs for 30-90 seconds.
import time# Trigger the analysisresp = rekko.post("/markets/kalshi/KXFED-26MAR19/analyze")analysis_id = resp.json()["analysis_id"]# Poll for completionwhile True: status = rekko.get( f"/markets/kalshi/KXFED-26MAR19/analyze/{analysis_id}/status" ).json() if status["status"] == "complete": break time.sleep(5)# Get the completed analysisanalysis = rekko.get("/markets/kalshi/KXFED-26MAR19/analysis").json()print(f"AI probability estimate: {analysis['probability']:.0%}")print(f"Market price: {market['yes_price']:.0%}")print(f"Edge: {analysis['edge']:+.0%}")print(f"Recommendation: {analysis['recommendation']}")
See the quickstart for the full trigger-poll-get pattern in all three languages.
Authentication failed (bad signature or expired timestamp)
403
Insufficient permissions
404
Market or resource not found
429
Rate limit exceeded
500
Server error
Implement exponential backoff for 429 and 5xx responses. Most HTTP libraries (including httpx with httpx.HTTPTransport(retries=3)) can handle this automatically.