Kalshi Sports Market Data API

Real-time sports prediction market data from Kalshi. Gzip-compressed, Redis-cached, structured with Pino logging.

REST API WebSocket OpenAPI 3.0 No Auth Required JSON
Base URL
http://localhost:4000
WebSocket
ws://localhost:4000/ws/v1
Auth
None — Public API
Data Refresh
Every 15 seconds

Quick Start

No API key needed. Just start making requests:

# Get all NBA game lines in one call
curl http://localhost:4000/api/prices/summary?sport=NBA

# Get live contract prices (ultra-slim, lowest latency)
curl http://localhost:4000/api/prices?sport=NBA&side=YES

# Search for a team
curl http://localhost:4000/api/search?q=Boston

# Full event details with all markets and contracts
curl http://localhost:4000/api/events?sport=NBA&limit=5

Data Model

Each sport has a simple hierarchy:

Sport (NBA, MLB, NFL, NHL)
  └── Event (a game — e.g. "Brooklyn at Toronto")
        └── Market (a prediction — e.g. "Winner?", one per team)
              └── Contract (YES/NO side — price is 0.00–1.00)

Prices are in dollar terms. A YES price of $0.60 = 60% implied probability.
Each game typically has 2 markets × 2 contracts = 4 contracts total.

Response Format

All list endpoints return a standardized envelope:

{
  "data": [ ... ],           // Array of results
  "meta": {
    "count": 15,            // Items in this response
    "total": 86,            // Total matching (for pagination)
    "cached": false,        // true if served from Redis cache
    "took_ms": 3.2          // Server processing time
  }
}

Response Headers

HeaderDescription
X-Response-TimeServer processing time (e.g. 2.3ms)
X-CacheHIT = served from Redis, MISS = fresh from DB
X-Cache-TTLCache time-to-live for this endpoint (e.g. 5s)
Content-Encodinggzip when client sends Accept-Encoding: gzip

Errors

All errors follow a consistent shape:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Market 'abc' not found"
  },
  "meta": { "cached": false, "took_ms": 1.2 }
}
HTTP StatusCodeWhen
400INVALID_QUERYSearch query too short or invalid parameters
404NOT_FOUNDResource doesn't exist
500INTERNAL_ERRORUnexpected server error

Endpoints

GET /health Service health check

Returns service status. Not cached.

GET /api/sports List sports with counts

Returns available sports with active market and event counts.

Response

FieldTypeDescription
sportstringSport code (NBA, MLB, NFL, NHL)
market_countintegerNumber of open markets
event_countintegerTotal events tracked
GET /api/prices ⚡ Ultra-slim flat price feed

Lowest-latency endpoint. One flat row per active contract with computed mid-price and spread. No nesting. Designed for ticker displays.

Parameters

ParamTypeDescription
sportstringFilter by sport: NBA, MLB, NFL, NHL
sidestringFilter by contract side: YES or NO

Response fields

FieldTypeDescription
symbolstringFull contract symbol
teamstringTeam name extracted from market subtitle
lastnumberLast trade price (0.00–1.00)
bidnumberBest bid price
asknumberBest ask price
midnumberMid-point of bid/ask
spreadnumberBid-ask spread
vol24hinteger24-hour volume
oiintegerOpen interest
GET /api/prices/summary ⚡ Game-level price summary

One row per game with both team lines. Includes last, bid, ask, mid for each team.

Parameters

ParamTypeDescription
sportstringFilter by sport
GET /api/events List events with nested markets

Paginated list of games with nested markets and contracts.

Parameters

ParamTypeDefaultDescription
sportstringFilter by sport
statusstringFilter: scheduled, open, closed, settled
limitinteger50Results per page (max 200)
offsetinteger0Pagination offset
GET /api/events/:id Single event detail

Get a single event by UUID or Kalshi event ticker (e.g. KXNBAGAME-26APR12BKNTOR).

GET /api/markets List markets with contracts

Paginated list of prediction markets. Same parameters as /api/events.

GET /api/markets/:id Single market detail

Get a single market by UUID. Includes full contract details, event context, rules, and game info.

GET /api/contracts/:id Single contract detail

Get a single YES/NO contract by UUID. Returns last price, bid, ask, volume, open interest, and parent market title.

GET /api/contracts/:id/price-history Contract price history

Time series of price snapshots for a contract.

Parameters

ParamTypeDefaultDescription
periodstring24hLookback: 1h, 6h, 24h, 7d, 30d

Response

FieldTypeDescription
pricenumberTrade price at this point
bid_pricenumberBid at time of recording
ask_pricenumberAsk at time of recording
volumeintegerVolume at time of recording
recorded_atdatetimeISO 8601 timestamp

WebSocket API

Connect to ws://localhost:4000/ws/v1 for real-time streaming.

Channels

ChannelDescription
sport:NBAAll NBA market updates
event:<ID>All markets for a specific game
market:<ID>Single market updates
allEverything

Actions

// Subscribe to NBA
{"action": "subscribe", "channel": "sport:NBA"}

// Unsubscribe
{"action": "unsubscribe", "channel": "sport:NBA"}

// Request a full snapshot
{"action": "snapshot", "channel": "sport:NBA"}

// Switch to delta mode (only changed fields)
{"action": "set_mode", "mode": "delta"}

// Heartbeat
{"action": "ping"}

Message Types

TypeWhen
welcomeOn connect — includes protocol docs
snapshotFull channel data after subscribe/snapshot
quoteReal-time price update
infoSubscription confirmations
pongResponse to ping
errorError messages
Kalshi Sports Market Data API v2.0.0  ·  Swagger UI  ·  OpenAPI Spec  ·  JSON Docs