kalshi

Original🇺🇸 English
Translated

Kalshi is a regulated prediction market exchange. Use this skill to interact with the Kalshi API for market data, trading, portfolio management, WebSocket streaming, and historical data retrieval.

2installs
Added on

NPX Install

npx skill4agent add outsharp/shipp-skills kalshi

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:
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)

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

Base URLs

EnvironmentREST APIWebSocket
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.

Documentation & References

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

Authentication

Kalshi uses RSA-PSS signed requests (not Bearer tokens). Every authenticated request requires three headers:
HeaderValue
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.

Python Signing Example

python
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

javascript
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:
SDKInstallDocs
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
.
For production applications, consider generating your own client from the OpenAPI spec.

Rate Limits

TierReadWrite
Basic20/s10/s
Advanced30/s30/s
Premier100/s100/s
Prime400/s400/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).

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).

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

EndpointMethodAuthDescription
/markets
GETNoList markets with filters (status, series, timestamps). Docs: Get Markets
/markets/{ticker}
GETNoGet a single market by ticker. Docs: Get Market
/markets/{ticker}/orderbook
GETNoGet current orderbook (yes bids + no bids). Docs: Get Market Orderbook
/markets/{ticker}/candlesticks
GETNoCandlestick data (1m, 1h, 1d). Docs: Get Market Candlesticks
/markets/candlesticks
POSTNoBatch candlesticks for up to 100 tickers. Docs: Batch Get Market Candlesticks
/markets/trades
GETNoAll public trades. Docs: Get Trades
/series/{ticker}
GETNoGet a series. Docs: Get Series
/series
GETNoList series. Docs: Get Series List

Events

EndpointMethodAuthDescription
/events
GETNoList events (excludes multivariate). Docs: Get Events
/events/{ticker}
GETNoGet a single event. Docs: Get Event
/events/{ticker}/metadata
GETNoEvent metadata only. Docs: Get Event Metadata
/events/{ticker}/candlesticks
GETNoAggregated event candlesticks. Docs: Get Event Candlesticks
/events/{ticker}/forecast/percentile_history
GETNoForecast percentile history. Docs: Get Event Forecast Percentile History
/events/multivariate
GETNoList multivariate events. Docs: Get Multivariate Events

Orders (Authenticated)

EndpointMethodAuthDescription
/portfolio/orders
POSTYesCreate an order. Docs: Create Order
/portfolio/orders
GETYesList your orders (resting/canceled/executed). Docs: Get Orders
/portfolio/orders/{order_id}
GETYesGet a single order. Docs: Get Order
/portfolio/orders/{order_id}
DELETEYesCancel an order. Docs: Cancel Order
/portfolio/orders/{order_id}/amend
POSTYesAmend price/count. Docs: Amend Order
/portfolio/orders/{order_id}/decrease
POSTYesDecrease contract count. Docs: Decrease Order
/portfolio/orders/{order_id}/queue_position
GETYesQueue position. Docs: Get Order Queue Position
/portfolio/orders/queue_positions
GETYesQueue positions for all resting orders. Docs: Get Queue Positions for Orders
/portfolio/orders/batched
POSTYesBatch create (up to 20). Docs: Batch Create Orders
/portfolio/orders/batched
DELETEYesBatch cancel (up to 20). Docs: Batch Cancel Orders

Portfolio (Authenticated)

EndpointMethodAuthDescription
/portfolio/balance
GETYesAccount balance (cents). Docs: Get Balance
/portfolio/positions
GETYesMarket positions. Docs: Get Positions
/portfolio/fills
GETYesYour fills. Docs: Get Fills
/portfolio/settlements
GETYesSettlement history. Docs: Get Settlements
/portfolio/resting_order_value
GETYesTotal resting order value (FCM). Docs: Get Total Resting Order Value

Subaccounts (Authenticated)

EndpointMethodAuthDescription
/portfolio/subaccounts
POSTYesCreate subaccount (max 32). Docs: Create Subaccount
/portfolio/subaccounts/balances
GETYesAll subaccount balances. Docs: Get All Subaccount Balances
/portfolio/subaccounts/transfers
GETYesSubaccount transfer history. Docs: Get Subaccount Transfers
/portfolio/subaccounts/transfer
POSTYesTransfer 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.
EndpointMethodAuthDescription
/portfolio/order_groups
POSTYesCreate group. Docs: Create Order Group
/portfolio/order_groups
GETYesList groups. Docs: Get Order Groups
/portfolio/order_groups/{id}
GETYesGet group. Docs: Get Order Group
/portfolio/order_groups/{id}
DELETEYesDelete group. Docs: Delete Order Group
/portfolio/order_groups/{id}/reset
POSTYesReset counter. Docs: Reset Order Group
/portfolio/order_groups/{id}/trigger
POSTYesManually trigger. Docs: Trigger Order Group
/portfolio/order_groups/{id}/limit
PUTYesUpdate limit. Docs: Update Order Group Limit

Communications / RFQ (Authenticated)

EndpointMethodAuthDescription
/communications/id
GETYesGet your comms ID. Docs: Get Communications ID
/rfqs
POSTYesCreate RFQ (max 100 open). Docs: Create RFQ
/rfqs
GETYesList RFQs. Docs: Get RFQs
/rfqs/{id}
GETYesGet RFQ. Docs: Get RFQ
/rfqs/{id}
DELETEYesDelete RFQ. Docs: Delete RFQ
/quotes
POSTYesCreate quote. Docs: Create Quote
/quotes
GETYesList quotes. Docs: Get Quotes
/quotes/{id}
GETYesGet quote. Docs: Get Quote
/quotes/{id}
DELETEYesDelete quote. Docs: Delete Quote
/quotes/{id}/accept
POSTYesAccept quote. Docs: Accept Quote
/quotes/{id}/confirm
POSTYesConfirm quote. Docs: Confirm Quote

Historical Data (Authenticated)

Historical data is for archived markets, orders, and fills that have moved past cutoff timestamps.
EndpointMethodAuthDescription
/historical/cutoff_timestamps
GETYesCutoff boundaries. Docs: Get Historical Cutoff Timestamps
/historical/markets
GETYesArchived markets. Docs: Get Historical Markets
/historical/markets/{ticker}
GETYesSingle archived market. Docs: Get Historical Market
/historical/markets/{ticker}/candlesticks
GETYesArchived candlesticks. Docs: Get Historical Market Candlesticks
/historical/fills
GETYesArchived fills. Docs: Get Historical Fills
/historical/orders
GETYesArchived orders. Docs: Get Historical Orders

Multivariate Collections

EndpointMethodAuthDescription
/multivariate/collections
GETNoList collections. Docs: Get Multivariate Event Collections
/multivariate/collections/{ticker}
GETNoGet collection. Docs: Get Multivariate Event Collection
/multivariate/collections/{ticker}/markets
POSTYesCreate market in collection. Docs: Create Market In Multivariate Event Collection
/multivariate/collections/{ticker}/lookup
GETNoLookup tickers. Docs: Lookup Tickers For Market In Multivariate Event Collection
/multivariate/collections/{ticker}/lookup_history
GETNoRecent lookups. Docs: Get Multivariate Event Collection Lookup History

Milestones & Structured Targets

EndpointMethodAuthDescription
/milestones
GETNoList milestones. Docs: Get Milestones
/milestones/{id}
GETNoGet milestone. Docs: Get Milestone
/structured_targets
GETNoList structured targets. Docs: Get Structured Targets
/structured_targets/{id}
GETNoGet structured target. Docs: Get Structured Target

Live Data

EndpointMethodAuthDescription
/live_data/{milestone_id}
GETNoLive data for milestone. Docs: Get Live Data
/live_data
GETNoMultiple milestones. Docs: Get Multiple Live Data

Search & Discovery

EndpointMethodAuthDescription
/search/sports/filters
GETNoSport filters. Docs: Get Filters for Sports
/search/tags
GETNoTags by category. Docs: Get Tags for Series Categories

Exchange & Account

EndpointMethodAuthDescription
/exchange/status
GETNoExchange status. Docs: Get Exchange Status
/exchange/schedule
GETNoExchange schedule. Docs: Get Exchange Schedule
/exchange/announcements
GETNoAnnouncements. Docs: Get Exchange Announcements
/exchange/data_timestamp
GETYesData freshness timestamp. Docs: Get User Data Timestamp
/exchange/series_fee_changes
GETNoFee changes. Docs: Get Series Fee Changes
/account/api_limits
GETYesYour rate limit tier. Docs: Get Account API Limits
/account/api_keys
GETYesList API keys. Docs: Get API Keys
/account/api_keys
POSTYesCreate API key. Docs: Create API Key
/account/api_keys/generate
POSTYesGenerate key pair. Docs: Get API Keys
/account/api_keys/{id}
DELETEYesDelete API key. Docs: Delete API Key

Incentive Programs

EndpointMethodAuthDescription
/incentives
GETNoList 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

ChannelAuth RequiredDescriptionDocs
ticker
No*Market price/volume/OI updatesMarket Ticker
trade
No*Public trade notificationsPublic Trades
market_lifecycle_v2
No*Market/event state changesMarket & Event Lifecycle
multivariate
No*Multivariate lookup notificationsMultivariate Lookups
orderbook_delta
YesReal-time orderbook updatesOrderbook Updates
fill
YesYour fill notificationsUser Fills
order
YesYour order updatesUser Orders
market_positions
YesYour position updatesMarket Positions
communications
YesRFQ/quote notificationsCommunications
order_group_updates
YesOrder group lifecycleOrder Group Updates
*The connection itself always requires authentication, even for public channels.

Subscribe Command

json
{
  "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

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

FIX Protocol

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

Common Patterns

Fetch All Open Markets for a Series

bash
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

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

Paginate Through All Results

bash
# 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

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

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

bash
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.