kalshi

SKILL.md

Kalshi API

Kalshi is a CFTC-regulated prediction market exchange where users trade on the outcomes of real-world events.

Check this skill and the official documentation FREQUENTLY. The canonical machine-readable index of all docs lives at:

https://docs.kalshi.com/llms.txt

Always consult llms.txt to discover every available page before building. It is the single source of truth for endpoint references, SDK docs, WebSocket channels, FIX protocol details, and getting-started guides.


Key Concepts (Glossary)

Term Definition
Market A single binary outcome contract (Yes / No) with prices in cents (1–99¢).
Event A collection of related markets representing a real-world occurrence (e.g., an election, a weather reading).
Series A template for recurring events that share the same structure and rules (e.g., "Daily Highest Temp in NYC").
Orderbook Bids only — in binary markets a YES bid at X¢ is equivalent to a NO ask at (100−X)¢.
Fill A matched trade on one of your orders.
Settlement The final resolution of a market (Yes or No) after determination.
Multivariate Event A combo event created dynamically from a multivariate event collection.

Full glossary: https://docs.kalshi.com/getting_started/terms.md


Base URLs

Environment REST API WebSocket
Production https://api.elections.kalshi.com/trade-api/v2 wss://api.elections.kalshi.com/trade-api/ws/v2
Demo https://demo-api.kalshi.co/trade-api/v2 wss://demo-api.kalshi.co/trade-api/ws/v2

Note: Despite the elections subdomain, the production URL serves ALL Kalshi markets — economics, weather, tech, entertainment, etc.

Demo environment info: https://docs.kalshi.com/getting_started/demo_env.md


Documentation & References

All detailed examples, request/response schemas, and walkthroughs live in the official docs. Always consult these before building:

Resource URL
Full documentation index (llms.txt) https://docs.kalshi.com/llms.txt
Introduction https://docs.kalshi.com/welcome/index.md
Making your first request https://docs.kalshi.com/getting_started/making_your_first_request.md
Quick Start: Market Data https://docs.kalshi.com/getting_started/quick_start_market_data.md
Quick Start: Authenticated Requests https://docs.kalshi.com/getting_started/quick_start_authenticated_requests.md
Quick Start: Create Your First Order https://docs.kalshi.com/getting_started/quick_start_create_order.md
Quick Start: WebSockets https://docs.kalshi.com/getting_started/quick_start_websockets.md
API Keys guide https://docs.kalshi.com/getting_started/api_keys.md
Rate Limits & Tiers https://docs.kalshi.com/getting_started/rate_limits.md
Pagination https://docs.kalshi.com/getting_started/pagination.md
Orderbook Responses https://docs.kalshi.com/getting_started/orderbook_responses.md
Historical Data https://docs.kalshi.com/getting_started/historical_data.md
Subpenny Pricing https://docs.kalshi.com/getting_started/subpenny_pricing.md
Fixed-Point Contracts https://docs.kalshi.com/getting_started/fixed_point_contracts.md
OpenAPI Spec (YAML) https://docs.kalshi.com/openapi.yaml
API Changelog https://docs.kalshi.com/changelog/index.md
Kalshi Platform https://kalshi.com
Demo Platform https://demo.kalshi.co

Authentication

Kalshi uses RSA-PSS signed requests (not Bearer tokens). Every authenticated request requires three headers:

Header Value
KALSHI-ACCESS-KEY Your API Key ID
KALSHI-ACCESS-TIMESTAMP Current Unix timestamp in milliseconds
KALSHI-ACCESS-SIGNATURE Base64-encoded RSA-PSS signature of {timestamp}{METHOD}{path}

Important: When signing, use the path without query parameters. For example, sign /trade-api/v2/portfolio/orders even if the request URL is /trade-api/v2/portfolio/orders?limit=5.

Generating API Keys

  1. Log in → Account Settings → API Keys section.
  2. Click "Create New API Key" to generate an RSA key pair.
  3. Store the private key immediately — it cannot be retrieved again.

Full guide: https://docs.kalshi.com/getting_started/api_keys.md

Python Signing Example

import base64, datetime, requests
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding

def load_private_key(file_path):
    with open(file_path, "rb") as f:
        return serialization.load_pem_private_key(f.read(), password=None)

def sign_pss(private_key, text: str) -> str:
    sig = private_key.sign(
        text.encode("utf-8"),
        padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.DIGEST_LENGTH),
        hashes.SHA256(),
    )
    return base64.b64encode(sig).decode("utf-8")

def kalshi_headers(key_id, private_key, method, path):
    ts = str(int(datetime.datetime.now().timestamp() * 1000))
    path_no_qs = path.split("?")[0]
    sig = sign_pss(private_key, ts + method + path_no_qs)
    return {
        "KALSHI-ACCESS-KEY": key_id,
        "KALSHI-ACCESS-SIGNATURE": sig,
        "KALSHI-ACCESS-TIMESTAMP": ts,
    }

JavaScript Signing Example

const crypto = require("crypto");
const fs = require("fs");

function signPss(privateKeyPem, text) {
  const sign = crypto.createSign("RSA-SHA256");
  sign.update(text);
  sign.end();
  return sign.sign({
    key: privateKeyPem,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
    saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST,
  }).toString("base64");
}

function kalshiHeaders(keyId, privateKeyPem, method, path) {
  const ts = Date.now().toString();
  const pathNoQs = path.split("?")[0];
  const sig = signPss(privateKeyPem, ts + method + pathNoQs);
  return {
    "KALSHI-ACCESS-KEY": keyId,
    "KALSHI-ACCESS-SIGNATURE": sig,
    "KALSHI-ACCESS-TIMESTAMP": ts,
  };
}

SDKs

Kalshi provides official SDKs. Prefer these for production integrations:

SDK Install Docs
Python (sync) pip install kalshi_python_sync https://docs.kalshi.com/sdks/python/quickstart.md
Python (async) pip install kalshi_python_async https://docs.kalshi.com/sdks/python/quickstart.md
TypeScript npm install kalshi-typescript https://docs.kalshi.com/sdks/typescript/quickstart.md

The old kalshi-python package is deprecated. Migrate to kalshi_python_sync or kalshi_python_async.

SDK overview: https://docs.kalshi.com/sdks/overview.md

For production applications, consider generating your own client from the OpenAPI spec.


Rate Limits

Tier Read Write
Basic 20/s 10/s
Advanced 30/s 30/s
Premier 100/s 100/s
Prime 400/s 400/s

Write-limited endpoints: CreateOrder, CancelOrder, AmendOrder, DecreaseOrder, BatchCreateOrders, BatchCancelOrders. In batch APIs each item counts as 1 transaction (except BatchCancelOrders where each cancel = 0.2 transactions).

Full details: https://docs.kalshi.com/getting_started/rate_limits.md


Pagination

The API uses cursor-based pagination. Responses include a cursor field; pass it as ?cursor={value} on the next request. An empty/null cursor means no more pages. Default page size is 100 (max typically 1000).

Full guide: https://docs.kalshi.com/getting_started/pagination.md


REST API Endpoints Overview

Below is a summary organized by domain. For full request/response schemas, see the linked docs or browse https://docs.kalshi.com/llms.txt.

Markets

Endpoint Method Auth Description
/markets GET No List markets with filters (status, series, timestamps). Docs: Get Markets
/markets/{ticker} GET No Get a single market by ticker. Docs: Get Market
/markets/{ticker}/orderbook GET No Get current orderbook (yes bids + no bids). Docs: Get Market Orderbook
/markets/{ticker}/candlesticks GET No Candlestick data (1m, 1h, 1d). Docs: Get Market Candlesticks
/markets/candlesticks POST No Batch candlesticks for up to 100 tickers. Docs: Batch Get Market Candlesticks
/markets/trades GET No All public trades. Docs: Get Trades
/series/{ticker} GET No Get a series. Docs: Get Series
/series GET No List series. Docs: Get Series List

Events

Endpoint Method Auth Description
/events GET No List events (excludes multivariate). Docs: Get Events
/events/{ticker} GET No Get a single event. Docs: Get Event
/events/{ticker}/metadata GET No Event metadata only. Docs: Get Event Metadata
/events/{ticker}/candlesticks GET No Aggregated event candlesticks. Docs: Get Event Candlesticks
/events/{ticker}/forecast/percentile_history GET No Forecast percentile history. Docs: Get Event Forecast Percentile History
/events/multivariate GET No List multivariate events. Docs: Get Multivariate Events

Orders (Authenticated)

Endpoint Method Auth Description
/portfolio/orders POST Yes Create an order. Docs: Create Order
/portfolio/orders GET Yes List your orders (resting/canceled/executed). Docs: Get Orders
/portfolio/orders/{order_id} GET Yes Get a single order. Docs: Get Order
/portfolio/orders/{order_id} DELETE Yes Cancel an order. Docs: Cancel Order
/portfolio/orders/{order_id}/amend POST Yes Amend price/count. Docs: Amend Order
/portfolio/orders/{order_id}/decrease POST Yes Decrease contract count. Docs: Decrease Order
/portfolio/orders/{order_id}/queue_position GET Yes Queue position. Docs: Get Order Queue Position
/portfolio/orders/queue_positions GET Yes Queue positions for all resting orders. Docs: Get Queue Positions for Orders
/portfolio/orders/batched POST Yes Batch create (up to 20). Docs: Batch Create Orders
/portfolio/orders/batched DELETE Yes Batch cancel (up to 20). Docs: Batch Cancel Orders

Portfolio (Authenticated)

Endpoint Method Auth Description
/portfolio/balance GET Yes Account balance (cents). Docs: Get Balance
/portfolio/positions GET Yes Market positions. Docs: Get Positions
/portfolio/fills GET Yes Your fills. Docs: Get Fills
/portfolio/settlements GET Yes Settlement history. Docs: Get Settlements
/portfolio/resting_order_value GET Yes Total resting order value (FCM). Docs: Get Total Resting Order Value

Subaccounts (Authenticated)

Endpoint Method Auth Description
/portfolio/subaccounts POST Yes Create subaccount (max 32). Docs: Create Subaccount
/portfolio/subaccounts/balances GET Yes All subaccount balances. Docs: Get All Subaccount Balances
/portfolio/subaccounts/transfers GET Yes Subaccount transfer history. Docs: Get Subaccount Transfers
/portfolio/subaccounts/transfer POST Yes Transfer between subaccounts. Docs: Transfer Between Subaccounts

Order Groups (Authenticated)

Order groups apply a rolling 15-second contracts limit; when hit, all orders in the group are auto-cancelled.

Endpoint Method Auth Description
/portfolio/order_groups POST Yes Create group. Docs: Create Order Group
/portfolio/order_groups GET Yes List groups. Docs: Get Order Groups
/portfolio/order_groups/{id} GET Yes Get group. Docs: Get Order Group
/portfolio/order_groups/{id} DELETE Yes Delete group. Docs: Delete Order Group
/portfolio/order_groups/{id}/reset POST Yes Reset counter. Docs: Reset Order Group
/portfolio/order_groups/{id}/trigger POST Yes Manually trigger. Docs: Trigger Order Group
/portfolio/order_groups/{id}/limit PUT Yes Update limit. Docs: Update Order Group Limit

Communications / RFQ (Authenticated)

Endpoint Method Auth Description
/communications/id GET Yes Get your comms ID. Docs: Get Communications ID
/rfqs POST Yes Create RFQ (max 100 open). Docs: Create RFQ
/rfqs GET Yes List RFQs. Docs: Get RFQs
/rfqs/{id} GET Yes Get RFQ. Docs: Get RFQ
/rfqs/{id} DELETE Yes Delete RFQ. Docs: Delete RFQ
/quotes POST Yes Create quote. Docs: Create Quote
/quotes GET Yes List quotes. Docs: Get Quotes
/quotes/{id} GET Yes Get quote. Docs: Get Quote
/quotes/{id} DELETE Yes Delete quote. Docs: Delete Quote
/quotes/{id}/accept POST Yes Accept quote. Docs: Accept Quote
/quotes/{id}/confirm POST Yes Confirm quote. Docs: Confirm Quote

Historical Data (Authenticated)

Historical data is for archived markets, orders, and fills that have moved past cutoff timestamps.

Endpoint Method Auth Description
/historical/cutoff_timestamps GET Yes Cutoff boundaries. Docs: Get Historical Cutoff Timestamps
/historical/markets GET Yes Archived markets. Docs: Get Historical Markets
/historical/markets/{ticker} GET Yes Single archived market. Docs: Get Historical Market
/historical/markets/{ticker}/candlesticks GET Yes Archived candlesticks. Docs: Get Historical Market Candlesticks
/historical/fills GET Yes Archived fills. Docs: Get Historical Fills
/historical/orders GET Yes Archived orders. Docs: Get Historical Orders

Historical data guide: https://docs.kalshi.com/getting_started/historical_data.md

Multivariate Collections

Endpoint Method Auth Description
/multivariate/collections GET No List collections. Docs: Get Multivariate Event Collections
/multivariate/collections/{ticker} GET No Get collection. Docs: Get Multivariate Event Collection
/multivariate/collections/{ticker}/markets POST Yes Create market in collection. Docs: Create Market In Multivariate Event Collection
/multivariate/collections/{ticker}/lookup GET No Lookup tickers. Docs: Lookup Tickers For Market In Multivariate Event Collection
/multivariate/collections/{ticker}/lookup_history GET No Recent lookups. Docs: Get Multivariate Event Collection Lookup History

Milestones & Structured Targets

Endpoint Method Auth Description
/milestones GET No List milestones. Docs: Get Milestones
/milestones/{id} GET No Get milestone. Docs: Get Milestone
/structured_targets GET No List structured targets. Docs: Get Structured Targets
/structured_targets/{id} GET No Get structured target. Docs: Get Structured Target

Live Data

Endpoint Method Auth Description
/live_data/{milestone_id} GET No Live data for milestone. Docs: Get Live Data
/live_data GET No Multiple milestones. Docs: Get Multiple Live Data

Search & Discovery

Endpoint Method Auth Description
/search/sports/filters GET No Sport filters. Docs: Get Filters for Sports
/search/tags GET No Tags by category. Docs: Get Tags for Series Categories

Exchange & Account

Endpoint Method Auth Description
/exchange/status GET No Exchange status. Docs: Get Exchange Status
/exchange/schedule GET No Exchange schedule. Docs: Get Exchange Schedule
/exchange/announcements GET No Announcements. Docs: Get Exchange Announcements
/exchange/data_timestamp GET Yes Data freshness timestamp. Docs: Get User Data Timestamp
/exchange/series_fee_changes GET No Fee changes. Docs: Get Series Fee Changes
/account/api_limits GET Yes Your rate limit tier. Docs: Get Account API Limits
/account/api_keys GET Yes List API keys. Docs: Get API Keys
/account/api_keys POST Yes Create API key. Docs: Create API Key
/account/api_keys/generate POST Yes Generate key pair. Docs: Get API Keys
/account/api_keys/{id} DELETE Yes Delete API key. Docs: Delete API Key

Incentive Programs

Endpoint Method Auth Description
/incentives GET No List incentives. Docs: Get Incentives

WebSocket API

A single authenticated WebSocket connection provides real-time streaming. Subscribe to channels by sending JSON commands.

Connection

wss://api.elections.kalshi.com/trade-api/ws/v2      (production)
wss://demo-api.kalshi.co/trade-api/ws/v2            (demo)

Authentication headers (KALSHI-ACCESS-KEY, KALSHI-ACCESS-SIGNATURE, KALSHI-ACCESS-TIMESTAMP) must be included during the handshake. Sign the string {timestamp}GET/trade-api/ws/v2.

Available Channels

Channel Auth Required Description Docs
ticker No* Market price/volume/OI updates Market Ticker
trade No* Public trade notifications Public Trades
market_lifecycle_v2 No* Market/event state changes Market & Event Lifecycle
multivariate No* Multivariate lookup notifications Multivariate Lookups
orderbook_delta Yes Real-time orderbook updates Orderbook Updates
fill Yes Your fill notifications User Fills
order Yes Your order updates User Orders
market_positions Yes Your position updates Market Positions
communications Yes RFQ/quote notifications Communications
order_group_updates Yes Order group lifecycle Order Group Updates

*The connection itself always requires authentication, even for public channels.

Subscribe Command

{
  "id": 1,
  "cmd": "subscribe",
  "params": {
    "channels": ["ticker", "orderbook_delta"],
    "market_tickers": ["KXHIGHNY-24JAN01-T60"]
  }
}

Keep-Alive

Kalshi sends Ping frames every 10 seconds with body heartbeat. Clients must respond with Pong frames. Docs: Connection Keep-Alive

Full WebSocket guide: https://docs.kalshi.com/getting_started/quick_start_websockets.md


Orderbook Structure

Kalshi orderbooks return bids only (no asks). In binary markets:

  • A YES bid at X¢ = a NO ask at (100−X)¢
  • A NO bid at Y¢ = a YES ask at (100−Y)¢

Each entry is [price, quantity] sorted ascending. The best bid is the last element.

Spread calculation:

  • Best YES ask = 100 - best_no_bid
  • Spread = Best YES ask − Best YES bid

Full guide: https://docs.kalshi.com/getting_started/orderbook_responses.md


FIX Protocol

Kalshi also supports the Financial Information eXchange (FIX) protocol for low-latency trading:

Topic Docs
Overview https://docs.kalshi.com/fix/index.md
Connectivity https://docs.kalshi.com/fix/connectivity.md
Session Management https://docs.kalshi.com/fix/session-management.md
Order Entry https://docs.kalshi.com/fix/order-entry.md
Order Groups https://docs.kalshi.com/fix/order-groups.md
Drop Copy https://docs.kalshi.com/fix/drop-copy.md
Market Settlement https://docs.kalshi.com/fix/market-settlement.md
RFQ Messages https://docs.kalshi.com/fix/rfq-messages.md
Error Handling https://docs.kalshi.com/fix/error-handling.md
Subpenny Pricing https://docs.kalshi.com/fix/subpenny-pricing.md

Common Patterns

Fetch All Open Markets for a Series

curl -s "https://api.elections.kalshi.com/trade-api/v2/markets?series_ticker=KXHIGHNY&status=open" | jq '.markets[] | {ticker, title, yes_price, volume}'

Get Orderbook for a Market

curl -s "https://api.elections.kalshi.com/trade-api/v2/markets/KXHIGHNY-24JAN01-T60/orderbook" | jq '.orderbook'

Paginate Through All Results

# First page
curl -s "https://api.elections.kalshi.com/trade-api/v2/markets?limit=100" > page1.json
# Extract cursor for next page
CURSOR=$(jq -r '.cursor' page1.json)
# Next page
curl -s "https://api.elections.kalshi.com/trade-api/v2/markets?limit=100&cursor=$CURSOR" > page2.json

Usage Tips

  • Always check llms.txt first: https://docs.kalshi.com/llms.txt has every endpoint and guide.
  • Use the demo environment for testing — credentials are separate from production.
  • Never hardcode API keys — use environment variables or secure key storage.
  • Prices are in cents (1–99). Monetary values in WebSocket position channels are in centi-cents (divide by 10,000 for dollars).
  • Sign paths without query parameters. Strip everything after ? before signing.
  • Handle pagination — always check for a non-null cursor and loop until exhausted.
  • Respect rate limits — implement exponential backoff on 429 responses.
  • Combine REST + WebSocket for the most accurate state: use REST for initial snapshots and WebSocket for real-time deltas.
  • Orderbook is bids-only — derive asks via the 100−price complement.
  • Historical vs. Live data: Check cutoff timestamps to know whether to query live or historical endpoints.
  • For market status values, use: unopened, open, closed, settled.
  • Batch operations count against per-second write limits per item.

Error Handling

Standard HTTP error codes apply. The API returns JSON error bodies with descriptive messages. Implement retry with backoff for 429 (rate limited) and 5xx (server errors).

WebSocket Error Codes

Code Meaning
1 Unable to process message
2 Params required
3 Channels required
5 Unknown command
8 Unknown channel name
9 Authentication required
14 Market ticker required
16 Market not found
17 Internal error
18 Command timeout

Full error code table: https://docs.kalshi.com/getting_started/quick_start_websockets.md


Example Project: Alph Bot

Alph Bot is an open-source automated trading bot that demonstrates a production-quality integration of the Kalshi API alongside Shipp for real-time sports data and Claude AI for probability estimation.

How Alph Bot Uses Kalshi

  1. Market discovery — Searches for Kalshi event contracts related to a live sports game (e.g., NBA point spreads, totals).
  2. Orderbook reading — Fetches orderbook data to determine current market-implied probabilities (prices in cents map directly to implied %).
  3. Edge detection — Compares Kalshi market prices against AI-estimated probabilities powered by Claude + Shipp real-time game data.
  4. Order execution — Places limit orders when sufficient edge is found, using Kelly Criterion for position sizing.
  5. Risk management — Enforces circuit breakers (max daily loss), position size limits, single-market exposure caps, and minimum account balance thresholds.

Alph Bot's Kalshi Configuration

From its .env.example:

ALPH_BOT_KALSHI_API_KEY_ID=abc123
ALPH_BOT_KALSHI_PRIVATE_KEY_PATH=./keys/kalshi-private.pem

# Strategy
ALPH_BOT_MIN_EDGE_PCT=5
ALPH_BOT_MIN_CONFIDENCE=medium
ALPH_BOT_KELLY_FRACTION=0.25

# Risk controls
ALPH_BOT_MAX_TOTAL_EXPOSURE_USD=10000
ALPH_BOT_MAX_POSITION_SIZE_USD=1000
ALPH_BOT_MAX_SINGLE_MARKET_PERCENT=20
ALPH_BOT_MAX_DAILY_LOSS_USD=500
ALPH_BOT_MAX_DAILY_TRADES=50
ALPH_BOT_MIN_ACCOUNT_BALANCE_USD=100

Try It

git clone https://gitlab.com/outsharp/shipp/alph-bot.git
cd alph-bot
cp .env.example .env
# Add your Kalshi, Shipp, and Anthropic API keys

yarn migrate

# Find a game to trade on
./index.ts available-games --sport NBA

# Run value betting in demo mode (uses Kalshi demo environment)
./index.ts value-bet -d --game <GAME_ID>

# Run in paper mode (no real orders executed)
./index.ts value-bet --paper --game <GAME_ID>

Warning: Trading on Kalshi involves real money when not in demo/paper mode. Always start with a demo account.

See the Alph Bot README for full setup instructions.


Versioning

The current API version is v2 under /trade-api/v2. Monitor the API Changelog for updates. SDK versions align with the OpenAPI spec and are generally published weekly.

Weekly Installs
39
GitHub Stars
2
First Seen
Feb 18, 2026
Installed on
codex38
opencode38
github-copilot36
kimi-cli36
gemini-cli36
amp36