Kalshi is a CFTC-regulated prediction market exchange where you can trade event contracts on politics, economics, weather, and more. Unlike Polymarket (which runs on Polygon), Kalshi is a traditional exchange with USD accounts, bank transfers, and regulatory oversight.
This guide takes you from zero to a working Kalshi trading bot. By the end, you will have a verified account, funded balance, working API credentials, and a minimal bot placing automated trades.
What You Will Learn
- How to create and verify a Kalshi account (including KYC)
- How to fund your account via bank transfer
- How to generate scoped API keys
- How to install and use Kalshi’s Python SDK
- How to write a minimal bot that fetches events and places orders
- How to test on Kalshi’s demo environment before going live
Prerequisites
- Eligible residency. Kalshi serves the US and 140+ other countries; UK, France, Canada, Australia, and ~50 other jurisdictions are excluded. US users need an SSN for KYC; international users need a government ID. Traders in excluded countries should use the Polymarket setup guide instead.
- Government-issued ID (plus SSN for US residents). Required for KYC verification.
- A US bank account. For funding via ACH transfer (US accounts only — international accounts fund via debit card, wire, or crypto).
- Python 3.10 or later installed on your machine.
- Basic Python knowledge — comfortable with pip, HTTP requests, and JSON parsing.
Step-by-Step Instructions
Step 1: Create Your Kalshi Account and Complete KYC
Go to kalshi.com and create an account. You will need:
- Email address and password
- Full legal name (must match your ID exactly)
- Date of birth
- Social Security Number (US residents only — international users verify identity and country of residence instead)
- A photo of your government-issued ID (driver’s license, passport, or state ID)
KYC verification typically completes within 1-2 business days. The automated check sometimes clears in minutes. You cannot access the API or trade until KYC is approved.
While waiting for KYC, you can explore Kalshi’s demo environment at demo-api.kalshi.co with paper money to familiarize yourself with the platform and API.
Step 2: Fund Your Account
Once KYC is approved, add funds via:
- ACH bank transfer (recommended). Free, takes 1-3 business days. Link your bank account in Settings > Funding.
- Wire transfer. Faster (same-day or next-day) but your bank may charge $15-30 for outgoing wires.
- Debit card. Instant but typically has a small fee and lower limits.
International accounts fund via debit card, wire transfer (minimum $1,000), or crypto — ACH is US-only.
Start with $100-500. You can always add more later. The minimum to place a single trade is technically $0.01 (one contract at the lowest price), but practical automated trading needs at least $50-100.
Step 3: Generate API Keys
Navigate to Settings > API Keys in your Kalshi account. Create a new API key with these permissions:
- Read: Enabled (fetch markets, positions, balances)
- Trade: Enabled (place and cancel orders)
- Withdraw: Disabled (never grant to a bot)
Save the API Key ID and Private Key securely. You will not be able to see the private key again after creation.
Store credentials in a .env file:
# .env — do not commit this file
KALSHI_API_KEY_ID=your_api_key_id
KALSHI_PRIVATE_KEY_PATH=/path/to/your/kalshi_private_key.pem
# Or inline:
KALSHI_API_SECRET=your_api_secret
Add to .gitignore:
echo ".env" >> .gitignore
echo "*.pem" >> .gitignore
Step 4: Install Dependencies and Test Connectivity
Install the required Python packages:
pip install requests python-dotenv cryptography
Verify your API connection using the official SDK:
pip install kalshi_python_sync
import os
from dotenv import load_dotenv
from kalshi_python_sync import Configuration, KalshiClient
load_dotenv()
# Configure SDK with RSA-PSS authentication
# Recommended demo host (legacy demo-api.kalshi.co still supported)
config = Configuration(
host="https://external-api.demo.kalshi.co/trade-api/v2"
)
config.api_key_id = os.getenv("KALSHI_API_KEY_ID")
with open(os.getenv("KALSHI_PRIVATE_KEY_PATH"), "r") as f:
config.private_key_pem = f.read()
client = KalshiClient(config)
# Test connection
balance = client.get_balance()
print(f"Connected to Kalshi successfully")
print(f"Available balance: ${balance.balance / 100:.2f}")
If this prints your balance, you are connected and ready to proceed. The old kalshi-python package and login/token authentication are deprecated — always use kalshi_python_sync with RSA-PSS key signing.
Step 5: Fetch Markets and Understand the Structure
Kalshi organizes contracts by events (a question like “Will inflation exceed 3% in March 2026?”) and markets (specific contracts within that event). Market data endpoints are public — no request signing needed — so a plain requests session works here:
import requests
# Recommended demo host (legacy demo-api.kalshi.co still supported)
KALSHI_API_BASE = "https://external-api.demo.kalshi.co/trade-api/v2"
session = requests.Session()
def fetch_active_events(session, limit=10):
"""Fetch active events from Kalshi."""
resp = session.get(
f"{KALSHI_API_BASE}/events",
params={"status": "open", "limit": limit}
)
events = resp.json().get("events", [])
return events
def fetch_markets_for_event(session, event_ticker):
"""Fetch all markets for a specific event."""
resp = session.get(
f"{KALSHI_API_BASE}/events/{event_ticker}"
)
return resp.json()
# List active events
events = fetch_active_events(session)
for event in events[:5]:
print(f"Event: {event['title']}")
print(f" Ticker: {event['event_ticker']}")
print(f" Category: {event.get('category', 'N/A')}")
print()
# Dive into a specific event
if events:
event_detail = fetch_markets_for_event(session, events[0]["event_ticker"])
for market in event_detail.get("markets", []):
print(f" Market: {market['title']}")
print(f" Ticker: {market['ticker']}")
print(f" Yes bid: ${market.get('yes_bid_dollars', 'N/A')}")
print(f" Yes ask: ${market.get('yes_ask_dollars', 'N/A')}")
print()
Step 6: Write Your Minimal Trading Bot
Here is a complete minimal bot that monitors a market and places an order when the price meets your criteria:
import os
import time
import requests
from dotenv import load_dotenv
load_dotenv()
# Production (legacy api.elections.kalshi.com still supported)
KALSHI_API_BASE = "https://external-api.kalshi.com/trade-api/v2"
API_KEY_ID = os.getenv("KALSHI_API_KEY_ID")
API_SECRET = os.getenv("KALSHI_API_SECRET")
# Configuration
MARKET_TICKER = "your-target-market-ticker" # e.g., "FED-RATE-26MAR-T5.25"
MAX_PRICE = "0.4500" # buy YES if price <= $0.45
ORDER_SIZE = "10.00" # number of contracts (fixed-point string)
PAPER_MODE = True # set False to trade for real
def authenticate():
"""Create authenticated session using RSA-PSS signing."""
# See the Kalshi API guide for full RSA-PSS implementation
from kalshi_python_sync import Configuration, KalshiClient
config = Configuration(host=KALSHI_API_BASE)
with open(os.getenv("KALSHI_PRIVATE_KEY_PATH"), "r") as f:
config.private_key_pem = f.read()
config.api_key_id = API_KEY_ID
return KalshiClient(config)
def get_market_price(client, ticker):
"""Get current YES ask price for a market (dollar string)."""
market = client.get_market(ticker)
return getattr(market, "yes_ask_dollars", None)
def place_order(client, ticker, side, price_dollars, count_fp):
"""Place a limit order on Kalshi."""
return client.create_order(
ticker=ticker,
action="buy",
side=side,
count_fp=count_fp,
yes_price_dollars=price_dollars,
)
def run():
from decimal import Decimal
max_price = Decimal(MAX_PRICE)
client = authenticate()
print(f"Bot started. Monitoring {MARKET_TICKER}")
print(f"Will buy YES at <= ${MAX_PRICE}")
print(f"Mode: {'PAPER' if PAPER_MODE else 'LIVE'}")
print()
while True:
try:
yes_ask = get_market_price(client, MARKET_TICKER)
if yes_ask is None:
print(f"[{time.strftime('%H:%M:%S')}] Market not found or no asks")
elif Decimal(yes_ask) <= max_price:
print(f"[{time.strftime('%H:%M:%S')}] Signal: YES ask ${yes_ask} <= ${MAX_PRICE}")
if PAPER_MODE:
print(f" [PAPER] Would buy {ORDER_SIZE} YES @ ${yes_ask}")
else:
result = place_order(client, MARKET_TICKER, "yes", yes_ask, ORDER_SIZE)
print(f" Order result: {result}")
else:
print(f"[{time.strftime('%H:%M:%S')}] YES ask ${yes_ask} — too expensive")
except requests.exceptions.RequestException as e:
print(f"[{time.strftime('%H:%M:%S')}] Network error: {e}")
except Exception as e:
print(f"[{time.strftime('%H:%M:%S')}] Error: {e}")
time.sleep(30)
if __name__ == "__main__":
run()
Step 7: Test on the Demo Environment First
Kalshi provides a demo environment. Switch your bot to demo mode by changing the base URL:
# Recommended demo host (legacy demo-api.kalshi.co still supported)
KALSHI_API_BASE = "https://external-api.demo.kalshi.co/trade-api/v2"
# Production (legacy api.elections.kalshi.com still supported)
# KALSHI_API_BASE = "https://external-api.kalshi.com/trade-api/v2"
Run the bot against the demo API for 1-3 days. Verify that orders place correctly, fills report accurately, and the bot handles edge cases (market not found, rate limits, clock skew on signed requests).
Step 8: Go Live and Set Up Monitoring
When demo testing is satisfactory, switch to the production URL, set PAPER_MODE = False, and start with small order sizes (5-10 contracts):
python kalshi_bot.py
For production operation, add basic logging and auto-restart:
import logging
logging.basicConfig(
filename="kalshi_bot.log",
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s"
)
# In your run loop, replace print() with logging.info()
logging.info(f"YES ask ${yes_ask/100:.2f} — order placed")
Use a process manager for auto-restart:
# Using systemd on Linux
sudo cat > /etc/systemd/system/kalshi-bot.service << 'EOF'
[Unit]
Description=Kalshi Trading Bot
After=network.target
[Service]
Type=simple
User=your_username
WorkingDirectory=/home/your_username/kalshi-bot
ExecStart=/usr/bin/python3 kalshi_bot.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable kalshi-bot
sudo systemctl start kalshi-bot
Kalshi Demo Environment: Endpoints and Setup
Kalshi’s demo environment is a full production mirror running on paper money — the same endpoints, payloads, and error responses, with none of the financial risk. The endpoints:
| Surface | Recommended endpoint | Legacy endpoint (still supported) |
|---|---|---|
| Demo REST | https://external-api.demo.kalshi.co/trade-api/v2 | https://demo-api.kalshi.co/trade-api/v2 |
| Demo WebSocket | wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2 | wss://demo-api.kalshi.co/trade-api/ws/v2 |
| Production REST | https://external-api.kalshi.com/trade-api/v2 | https://api.elections.kalshi.com/trade-api/v2 |
| Production WebSocket | wss://external-api-ws.kalshi.com/trade-api/ws/v2 | — |
Demo credentials are separate from production. Create a demo API key at demo.kalshi.co under account settings — the same read/trade/withdraw scoping applies. Because the demo API mirrors production exactly, going live is a base-URL swap plus your production key.
Kalshi Rate Limits for Bots
Kalshi enforces tiered API rate limits. The default Basic tier allows roughly 200 read and 100 write tokens per second, and a single order placement costs 10 write tokens — so a Basic-tier bot sustains about 10 orders per second before hitting 429s. Higher tiers (Advanced and up) are earned on trailing 30-day volume or self-serve upgrade. The polling loop in this guide (one market check every 30 seconds) sits nowhere near these limits, but a multi-market or market-making bot will. See the Kalshi API Guide for the full tier table and token accounting.
Common Mistakes and How to Avoid Them
Skipping the demo environment. Kalshi is one of the few prediction markets that offers a proper sandbox. Use it. There is no reason to test with real money when a free demo exists.
Granting withdrawal permissions to API keys. A bot never needs to withdraw funds. Scope your API key to read and trade only.
Not handling 401s correctly. With RSA-PSS key signing there is no session to expire — every request is signed independently. A 401 means clock skew (your KALSHI-ACCESS-TIMESTAMP fell outside the acceptance window — run NTP sync on your VPS) or a revoked key. Retrying without fixing the clock changes nothing.
Trading illiquid markets. Some Kalshi events have very thin order books. If your bot places a large order on an illiquid market, you will get filled at a poor price. Filter markets by daily volume (minimum $10,000 recommended).
Ignoring Kalshi’s fee structure. Kalshi’s taker fee is 0.07 × price × (1 − price) per contract on standard markets — a parabola peaking at $0.0175 per contract at 50¢ and shrinking toward the extremes. Premium categories use a higher coefficient. A strategy trading at mid-range prices must clear roughly 1.75¢ per contract in expected edge before it is viable. Factor the fee curve, not a flat rate, into every trading decision.
Cost Breakdown
| Cost Category | Typical Range | Notes |
|---|---|---|
| Kalshi account | Free | KYC required; US + 140+ countries served |
| Account funding | $100-500 to start | Via ACH (free) or wire ($15-30 bank fee) |
| Python SDK | Free | requests + standard libraries |
| Kalshi trading fees | ~$0.003-0.0175/contract | 0.07 × P × (1−P) taker formula; peaks at 50¢ |
| VPS (optional) | $5-15/month | For 24/7 operation |
| Demo environment | Free | Paper trading with demo money |
| Total first-month cost | $110-550 | Mostly initial capital deposit |
Kalshi’s cost structure is different from Polymarket — there are no gas fees or blockchain costs, but per-contract trading fees are explicit and can add up on high-volume strategies.
Next Steps and Related Guides
- Kalshi API Guide — Complete API reference for advanced bot development.
- How to Automate Prediction Market Trading — Platform-agnostic overview covering Kalshi, Polymarket, and more.
- How to Buy a Market-Making Bot for Kalshi — If you want to buy a pre-built bot instead of building from scratch.
- Prediction Market API Reference — Cross-platform API comparison including Kalshi.
- Kalshi Agents Platform Guide — Everything about the Kalshi bot ecosystem.
- Agent Betting Stack — How Kalshi bots fit into the four-layer agent architecture.
