# Kalshi API Reference (Verified Feb 14, 2026)

**Base URL:** `https://api.elections.kalshi.com`

## Key Findings

### Field Naming Mismatches (Critical)

| API returns                    | Code expects    | Where                                                                                                                      |
| ------------------------------ | --------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `series.ticker`                | `series_ticker` | `getSeries()` must map `ticker` → `series_ticker`                                                                          |
| `market.ticker`                | `market_ticker` | `getMarkets()` must map `ticker` → `market_ticker`                                                                         |
| `market.expiration_time`       | `expiry_time`   | Code checks `expiry_time` which doesn't exist — must use `expiration_time`                                                 |
| `market.yes_bid` (cents 0-100) | `yes_price`     | Code checks `yes_price` which doesn't exist on list endpoint — use `yes_bid`/`yes_ask`                                     |
| `market.status` = `"active"`   | `"open"`        | API uses `active` for live markets, not `open`. The `status=open` query param works but returns `status: "active"` objects |

### Pagination

- Response shape: `{ cursor: string, markets: [...] }`
- Cursor is present when more pages exist; absent/empty when no more
- `limit=200` is max per page
- **338 open men's CBB markets** right now (needs 2 pages)
- **294 open women's CBB markets** (needs 2 pages)
- **0 open NBA markets** at time of test (between game days)

### Market Counts by Sport (Open)

| Sport       | Series Ticker  | Open Markets | Pages Needed |
| ----------- | -------------- | ------------ | ------------ |
| CBB Men's   | `KXNCAAMBGAME` | 338          | 2            |
| CBB Women's | `KXNCAAWBGAME` | 294          | 2            |
| CBB (other) | `KXNCAABBGAME` | 74           | 1            |
| NBA         | `KXNBAGAME`    | 0 (off day)  | 1            |

---

## Endpoints

### GET /trade-api/v2/series

**Query params:** `category` (e.g., "Sports")

**Response:**

```json
{
  "series": [
    {
      "ticker": "KXNBAGAME",       // NOT "series_ticker"
      "title": "NBA games",
      "category": "Sports",
      "fee_multiplier": 1,
      "fee_type": "quadratic",
      "frequency": "custom",
      "tags": ["Basketball"],
      "settlement_sources": [...],
      "contract_terms_url": "...",
      "contract_url": "...",
      "additional_prohibitions": null
    }
  ]
}
```

**Key series tickers:**

- `KXNBAGAME` — NBA game winners
- `KXNCAAMBGAME` — College basketball men's game winners
- `KXNCAAWBGAME` — College basketball women's game winners
- `KXNCAABBGAME` — College basketball (other)
- `KXNFLGAME` — NFL game winners
- `KXMLBGAME` — MLB game winners
- `KXNHLGAME` — NHL game winners

### GET /trade-api/v2/markets

**Query params:** `series_ticker`, `event_ticker`, `status` ("open"), `limit` (max 200), `cursor`

**Response:**

```json
{
  "cursor": "CgwI5K3oywYQ...", // present if more pages
  "markets": [
    {
      "ticker": "KXNCAAMBGAME-26FEB16HOUISU-ISU", // NOT "market_ticker"
      "title": "Houston at Iowa St. Winner?",
      "subtitle": "",
      "yes_sub_title": "Iowa St.",
      "no_sub_title": "Iowa St.",
      "event_ticker": "KXNCAAMBGAME-26FEB16HOUISU",
      "status": "active", // NOT "open"
      "result": "",
      "market_type": "binary",
      "yes_bid": 13, // cents (0-100)
      "yes_ask": 67,
      "no_bid": 33,
      "no_ask": 87,
      "last_price": 81,
      "volume": 1,
      "open_interest": 1,
      "liquidity": 5321,
      "open_time": "2026-02-14T19:14:00Z",
      "close_time": "2026-03-03T02:00:00Z",
      "expiration_time": "2026-03-03T02:00:00Z", // NOT "expiry_time"
      "expected_expiration_time": "...",
      "latest_expiration_time": "...",
      "created_time": "...",
      "updated_time": "...",
      "tick_size": 1,
      "strike_type": "custom",
      "custom_strike": "...",
      "fractional_trading_enabled": false,
      "can_close_early": true,
      "response_price_units": "cents",
      "notional_value": 100,
      "price_level_structure": null,
      "price_ranges": null
    }
  ]
}
```

**Notes:**

- `yes_price` and `no_price` do NOT exist on list responses. Use `yes_bid`/`yes_ask`/`no_bid`/`no_ask`.
- Prices are in **cents** (0-100), not decimals.
- Without `status` filter, returns oldest (finalized) markets first.
- With `status=open`, returns active/upcoming markets.

### GET /trade-api/v2/markets/:ticker

**Response:**

```json
{
  "market": {
    /* same fields as above, plus: */ "rules_primary": "...",
    "rules_secondary": "...",
    "settlement_timer_seconds": 0
  }
}
```

### GET /trade-api/v2/markets/:ticker/orderbook

**Response:**

```json
{
  "orderbook": {
    "yes": [[1, 1327], [2, 2068], [3, 856], [10, 70]],     // [price_cents, quantity]
    "no": [[1, 1000], [2, 700], [3, 658], [4, 1266]],
    "yes_dollars": [...],
    "no_dollars": [...]
  },
  "orderbook_fp": { ... }
}
```

**Notes:**

- Each level is `[price_in_cents, quantity]`
- `yes` and `no` are arrays of bid levels, sorted low to high
- Path is `/markets/{ticker}/orderbook`, NOT `/orderbook/{ticker}`

### GET /trade-api/v2/events/:ticker

**Response:**

```json
{
  "event": {
    "event_ticker": "KXNCAAMBGAME-26FEB16HOUISU",
    "series_ticker": "KXNCAAMBGAME",
    "title": "Houston at Iowa St.",
    "sub_title": "HOU at ISU (Feb 16)",
    "category": "Sports",
    "mutually_exclusive": true,
    "collateral_return_type": "...",
    "available_on_brokers": [...],
    "product_metadata": { ... },
    "strike_period": "..."
  },
  "markets": [
    { /* full market objects for both sides of the game */ }
  ]
}
```

**Notes:**

- Each game event contains 2 markets (one per team — e.g., `-ISU` and `-HOU`)
- `event.title` has the clean game name (e.g., "Houston at Iowa St.")
- `event.sub_title` has abbreviated version (e.g., "HOU at ISU (Feb 16)")

---

## Code Issues Identified

1. **`nba.ts` checks `expiry_time`** — API returns `expiration_time`. Fix: use `expiration_time`.
2. **`nba.ts` checks `yes_price`/`no_price`** — These don't exist on list endpoints. Fix: use `yes_bid`/`yes_ask`.
3. **`kalshiApi.ts` getMarkets()** — Must normalize `ticker` → `market_ticker` (already done).
4. **`kalshiApi.ts` getSeries()** — Must normalize `ticker` → `series_ticker` (verify this mapping exists).
5. **No `status` filter** — Without `status=open`, getMarkets returns finalized (settled) markets first, wasting the 200-item limit on dead markets.
6. **No pagination** — CBB has 338+ open markets, exceeding the 200 limit. Need cursor pagination for full coverage.
