Skip to main content
skill CX Codex

kalshi-api — Claude Code skill: Kalshi exchange mechanics

A skill covering RSA-PSS signing, order schema and the YES/NO book on Kalshi. Useful when you write trading code against that API.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add agiprolabs/claude-trading-skills --skill kalshi-api -a claude-code
Open on GitHub

What kalshi-api does

This skill is the reference layer for the Kalshi API: base URL https://api.elections.kalshi.com/trade-api/v2, request signing, order body schema, the YES/NO book convention and an endpoint rundown. It stays market-type-agnostic, so the other Kalshi skills build on it.

Signing code ships with it, in Python: httpx plus cryptography, reading the key from KALSHI_PRIVATE_KEY_PATH and the id from KALSHI_KEY_ID. The signed string is {timestamp_ms}{METHOD}{path} with no query string, the timestamp is in milliseconds, and the salt length equals PSS.DIGEST_LENGTH. The book takes getting used to: yes and no are both resting bid ladders, there is no separate ask side, so the cost of buying NO works out as 1 − best_yes_bid.

Nothing is public — auth is required even for reads. The demo host demo-api.kalshi.co holds a near-empty book, so production is the one to use, reads included. Orders take dollar strings: count_fp as "1.00", yes_price_dollars as "0.01", and time_in_force is mandatory; sending type is not allowed. Only [A-Za-z0-9-] may appear in client_order_id, and strike tickers carry a dot, so never paste a ticker there. The old trading-api.kalshi.com host is dead and the order schema already moved from integer cents to dollar strings, so smoke-test your signing and order bodies against a live response before shipping.

What it helps with

  • sign a Kalshi request with an RSA-PSS key
  • read the YES/NO book and work out the entry price
  • build an order body in dollar-string format
  • pull candlestick history for a series market
  • check balance and positions over the API

Example prompts for the agent

  • Write a Python function that signs Kalshi requests using the key at KALSHI_PRIVATE_KEY_PATH
  • Work out the cost of buying NO from the book of KXHIGHNY-26JUN02-B75.5
  • Build a buy order for 1 YES contract at 0.01 with time_in_force set to good_till_canceled

How to install kalshi-api

1Skills CLI (Vercel)

npx skills add agiprolabs/claude-trading-skills --skill kalshi-api -a claude-code

2Manually: put the files in place

~/.claude/skills/kalshi-api/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/kalshi-api/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about kalshi-api

How do I install kalshi-api in Claude Code?

Run npx skills add agiprolabs/claude-trading-skills --skill kalshi-api -a claude-code. The skill file lands at ~/.claude/skills/kalshi-api/SKILL.md.

What does the kalshi-api skill do?

It documents Kalshi exchange mechanics: RSA-PSS auth, the order schema, the YES/NO orderbook convention, WebSocket and the endpoint surface. Other Kalshi skills share it as a base layer.

What do I need before using it?

A key generated in the Kalshi dashboard, stored in KALSHI_KEY_ID and KALSHI_PRIVATE_KEY_PATH, plus the httpx and cryptography packages.

Source text

SKILL.md · MIT
---
name: kalshi-api
description: Kalshi exchange mechanics — RSA-PSS auth, order schema, YES/NO orderbook convention, WebSocket, and endpoint surface. Market-type-agnostic shared layer for all Kalshi skills.
---

# Kalshi API

CFTC-regulated US event exchange. USD-denominated binary contracts settle at $1.00 (YES wins) or $0.00 (NO wins). REST + WebSocket, RSA-PSS authentication on every request.

For contract semantics and settlement rules, see the `kalshi-weather-markets` and `kalshi-crypto-index-markets` skills. For strategy, sizing, and backtesting, see `prediction-market-strategy`.

---

> **VERIFY BEFORE CODING.**
> The Kalshi API has broken backward compatibility before: the host changed (old `trading-api.kalshi.com` → dead), and the order schema changed (integer cents → dollar strings). Always smoke-test signing and order bodies against a live response before shipping.
>
> Canonical sources:
> - API reference: <https://docs.kalshi.com> (legacy mirror: <https://trading-api.readme.io>)
> - Official Python starter: <https://github.com/Kalshi/kalshi-starter-code-python>

---

## Overview

- **Base URL:** `https://api.elections.kalshi.com/trade-api/v2`
- **Auth:** RSA-PSS on every request — there are no public/unauthenticated endpoints
- **No demo parity:** the demo environment (`demo-api.kalshi.co`) has a near-empty book; use production even for read-only pulls
- **Contracts:** $0.01–$0.99 per contract; pay price if YES wins, lose price if NO wins; max payout = $1.00

---

## Quick Start

### 1. Credentials

```
KALSHI_KEY_ID=<your-key-uuid>
KALSHI_PRIVATE_KEY_PATH=~/.kalshi/private.pem
```

Generate the key in the Kalshi dashboard. Store secrets in environment variables or a secrets manager — never in code.

### 2. Install

```bash
pip install httpx cryptography
```

### 3. Host + auth (the part everyone gets wrong)

The host and signature format are where implementations break. Three common failures:
1. Using the old `trading-api.kalshi.com` host → 401
2. Including the query string in the signed path → 401
3. Signing with seconds instead of milliseconds → 401

```python
import os, time, base64, httpx
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

BASE = "https://api.elections.kalshi.com/trade-api/v2"
KEY_ID = os.environ["KALSHI_KEY_ID"]
with open(os.environ["KALSHI_PRIVATE_KEY_PATH"], "rb") as f:
    PRIV = serialization.load_pem_private_key(f.read(), password=None)

def _headers(method: str, path: str) -> dict:
    """path must include /trade-api/v2 prefix and exclude query string."""
    ts = str(int(time.time() * 1000))             # milliseconds
    msg = f"{ts}{method}{path}".encode()
    sig = PRIV.sign(
        msg,
        padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
                    salt_length=padding.PSS.DIGEST_LENGTH),
        hashes.SHA256(),
    )
    return {
        "KALSHI-ACCESS-KEY": KEY_ID,
        "KALSHI-ACCESS-TIMESTAMP": ts,
        "KALSHI-ACCESS-SIGNATURE": base64.b64encode(sig).decode(),
    }

def get(path: str, params=None):
    # Sign the path only — query goes into params, not the signature
    r = httpx.get(BASE + path, params=params,
                  headers=_headers("GET", "/trade-api/v2" + path))
    r.raise_for_status()
    return r.json()

def post(path: str, body: dict):
    r = httpx.post(BASE + path, json=body,
                   headers=_headers("POST", "/trade-api/v2" + path))
    r.raise_for_status()
    return r.json()

# Example: open markets in a series
markets = get("/markets", params={"series_ticker": "KXHIGHNY", "status": "open"})
```

**Signature spec:** RSA-PSS, MGF1 over SHA-256, salt length = `PSS.DIGEST_LENGTH`. String to sign: `{timestamp_ms}{METHOD}{path}` where path includes `/trade-api/v2` and excludes the query string.

Headers: `KALSHI-ACCESS-KEY` (UUID), `KALSHI-ACCESS-TIMESTAMP` (ms), `KALSHI-ACCESS-SIGNATURE` (base64).

### 4. Candlestick history

```python
# Returns OHLC for yes_bid / yes_ask + volume + open_interest
# Values are dollar strings: {"close": "0.42"}
candles = get(
    f"/series/KXHIGHNY/markets/{ticker}/candlesticks",
    params={"start_ts": start_epoch, "end_ts": end_epoch, "period_interval": 60},
)
```

`period_interval` is in **minutes**: `1`, `60`, or `1440`.

---

## YES/NO Order-Book Convention

On Kalshi, **`yes` and `no` are both resting BID ladders** — there is no separate ask book. To take the other side you lift the opposing bid:

```
no_ask  = 1 − best_yes_bid    # cost to buy NO right now (lift YES bids)
yes_ask = 1 − best_no_bid     # cost to buy YES right now (lift NO bids)
P(YES) mid = (best_yes_bid + (1 − best_no_bid)) / 2
```

Getting this backwards silently inverts every signal. Use the helpers in `scripts/kalshi_orderbook.py`.

**Orderbook response** comes in two variants depending on API tier — normalize before using:
```json
{"orderbook": {"yes": [[price, size], ...], "no": [[price, size], ...]}}
```
If a price value is `> 1.0`, it is integer cents — divide by 100.

---

## Order Schema

`POST /trade-api/v2/portfolio/orders` uses **fixed-point dollar STRINGS**, not integers. The old schema (integer cents, `count`, `yes_price`) returns `400 invalid_parameters`.

```json
{
  "ticker": "KXHIGHNY-26JUN02-B75.5",
  "action": "buy",
  "side": "yes",
  "count_fp": "1.00",
  "yes_price_dollars": "0.01",
  "client_order_id": "my-strategy-001",
  "time_in_force": "good_till_canceled"
}
```

Critical field rules — each violation returns `400`:

| Field | Rule | Common mistake that 400s |
|---|---|---|
| `count_fp` | fixed-point **string** `"1.00"` | integer `count: 1` |
| `{side}_price_dollars` | dollar **string** `"0.01"` | integer cents `yes_price: 1` |
| `time_in_force` | **required**: `good_till_canceled` \| `immediate_or_cancel` \| `fill_or_kill` | omitted |
| `client_order_id` | `[A-Za-z0-9-]` only | `.` or `:` in the string — bracket tickers contain `.`, so never copy the ticker directly |
| `type` | **do not send** | `"type": "limit"` |

For the full order lifecycle (amend, decrease, cancel, batch) and `strike_type` gotchas, see `references/auth-and-orders.md`.

---

## Endpoint Summary

| Category | Endpoint | Notes |
|---|---|---|
| Balance | `GET /portfolio/balance` | — |
| Positions | `GET /portfolio/positions` | — |
| Orders | `GET /portfolio/orders` | `?status=resting\|canceled\|executed` |
| Place order | `POST /portfolio/orders` | dollar-string schema above |
| Cancel | `DELETE /portfolio/orders/{id}` | returns `{"order": {...status: "canceled"}}` |
| Amend | `POST /portfolio/orders/{id}/amend` | `ticker` required in body |
| Decrease | `POST /portfolio/orders/{id}/decrease` | `{"reduce_by_fp": "1.00"}` |
| Batch | `POST /portfolio/orders/batched` | `{"orders": [...]}` |
| Fills | `GET /portfolio/fills` | `?limit=N` |
| Settlements | `GET /portfolio/settlements` | `?limit=N` |
| Markets | `GET /markets` | `?series_ticker=&status=open&limit=500` |
| Orderbook | `GET /markets/{ticker}/orderbook` | `?depth=N` |
| Candlesticks | `GET /series/{series}/markets/{ticker}/candlesticks` | `?start_ts=&end_ts=&period_interval=60` |
| Trades | `GET /markets/trades` | recent trade prints |

Full endpoint surface, market metadata fields, and rate limits: `references/endpoints-and-marketdata.md`.
WebSocket discovery pipeline: `references/websocket.md`.

---

## Files

### References
- `references/auth-and-orders.md` — RSA-PSS spec, dollar-string order schema, `time_in_force`, `client_order_id` sanitization, amend/decrease/cancel lifecycle, `strike_type` gotcha, fees
- `references/endpoints-and-marketdata.md` — Full endpoint table, orderbook variants, market metadata fields (`result`, `open_time`, `close_time`, `series_ticker`), candlesticks, rate limits
- `references/websocket.md` — WS host, discovery pipeline, channels, signing the WS upgrade

### Scripts
- `scripts/kalshi_orderbook.py` — YES/NO bid-ladder helpers (`no_ask`, `yes_ask`, `p_yes_mid`, `overround`, `kalshi_fee`). Pure stdlib, no keys, runs offline.

© agiprolabs · MIT · agiprolabs/claude-trading-skills

Similar skills

All skills for Finance and business →

From the same set64

fixed-income A Python skill for bond price, yield-to-maturity, duration, and convexity calculations. It also documents planned DeFi lending-rate analysis. CX Codex +1 424installs dex-execution Runs Solana token swaps through the Jupiter aggregator: quote, build, sign and confirm, with a human check before signing. CX Codex +1 424installs tax-liability-tracking Keeps a running tax ledger for crypto trades: proportional cost basis, gain classification and signals that price in the tax hit. CX Codex +1 423installs shredstream A skill for streaming Solana transactions before the validator executes the block — 100-500ms ahead of standard Yellowstone gRPC. Built for time-critical trading strategies. CX Codex +1 423installs regulatory-reporting Prepares cryptocurrency trade data for IRS Form 8949 and Schedule D line items. Helps organize taxable dispositions before handing records to an accountant. CX Codex +1 420installs cost-basis-engine Computes cost basis for crypto trades with FIFO, LIFO, HIFO, specific ID and average cost, so you can compare the tax hit across methods. CX Codex +1 421installs raptor-dex Connects coding agents to a self-hosted Solana DEX aggregator with no rate limits. Helps route swaps across 25+ DEXes and submit transactions via Yellowstone Jet TPU. CX Codex +1 413installs prediction-market-strategy A strategy, position-sizing and backtesting layer for binary prediction markets such as Kalshi, Polymarket and ForecastEx. Useful when trade selection has to run on net edge instead of win rate. CX Codex +1 311installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor