---
title: "Watch up to 10 Kalshi traders by nickname"
method: GET
path: "/api/v1/watchlist"
tags: ["Live (API key)"]
---

# Watch up to 10 Kalshi traders by nickname

`GET /api/v1/watchlist`

## Request

- Base URL: `https://kalshispy.com`
- URL: `https://kalshispy.com/api/v1/watchlist`
- Auth: HTTP bearer

Up to 10 Kalshi traders by exact nickname, any public trader: coverage, ranking position, open positions largest first (value, cost, P&L, when opened), the markets they recently closed and a change log of their trades, newest first. One unit per call. Requires a KalshiSpy API key.

## Query parameters

- `traders` string, required
- `since` string: YYYY-MM-DD or ISO 8601 (UTC)
- `positions_limit` integer

## Response `200`

OK

- object
  - `ok` true, required
  - `data` Watchlist, required
    - `as_of` string, date-time, nullable: Send it as `since` to poll, and de-duplicate changes by id. The earliest trader as_of, or earlier where a trader's change log or closed list was cut (where it resumes); while any trader is unavailable, the `since` asked with (null without one), so the next poll covers that trader's gap.
    - `since` string, date-time, nullable: The `since` applied.
    - `traders` WatchTrader[]: One per nickname asked, in the order asked.
      - `nickname` string: As asked, exact.
      - `coverage` 'verified' | 'public' | 'private' | 'not_found' | 'unavailable': verified: on KalshiSpy's roster of ID-verified, high-profit traders. public: a public Kalshi trader outside the roster. private: the trader keeps their positions hidden. not_found: no Kalshi account has this exact nickname. unavailable: it could not be read this time; ask again shortly. Only verified and public carry positions, closed markets and changes.
      - `rank` integer, nullable: Position in KalshiSpy's public top-10 ranking. null when not ranked, and also when the ranking is not at hand on the server answering this call; it fills in on a later call.
      - `did_you_mean` string, nullable: not_found only: the account whose nickname matches this one in another case, if any. Ask for it under that spelling.
      - `kalshi_profile_url` string, uri, nullable
      - `as_of` string, date-time, nullable: When this trader's read started, at most a minute before the call. Positions and changes are as of then; a trade after it comes in the next answer.
      - `history_since` string, date-time, nullable: The oldest of the trader's recent trades in this answer: changes before it are not known. null when there are none.
      - `open_positions_count` integer, nullable: Every open position read (neither since nor positions_limit narrows it).
      - `open_value_usd` number, nullable: Sum of value_usd over every open position read.
      - `unrealized_pnl_usd` number, nullable: Sum of pnl_usd over every open position read.
      - `positions_complete` boolean, nullable: false when the trader holds more than one read takes (30 pages): the totals then cover the markets read, and traded markets not among them are left out of closed.
      - `positions_total` integer, nullable: How many positions this answer lists before positions_limit (after since).
      - `positions_truncated` boolean, nullable: true when positions_limit cut the list.
      - `changes_truncated` boolean, nullable: true when the trader had more changes than this answer lists (100).
      - `closed_truncated` boolean, nullable: true when the trader had more closed markets than this answer lists (100).
      - `positions` WatchPosition[]: Open positions, largest value first, up to positions_limit.
        - `ticker` string
        - `event_ticker` string
        - `series_ticker` string
        - `question` string
        - `outcome` string: Kalshi's short outcome label; empty for plain Yes/No markets.
        - `side` 'YES' | 'NO'
        - `contracts` number: Contracts held, to 0.01 (fractional contracts exist).
        - `value_usd` number, nullable: The position's value now: contracts × the side's value (the bid/ask midpoint, or the last trade on a wide or empty book), or the payout once the market is decided. null when the market has no price.
        - `cost_usd` number, nullable: What the position cost: value_usd − pnl_usd, never below 0. null when either is.
        - `pnl_usd` number, nullable: Unrealized P&L on the position, USD.
        - `opened_at` string, date-time, nullable: When this position was opened (from flat, or by flipping sides), when that is inside the trader's history window (history_since); null when it was already held then.
        - `last_trade_at` string, date-time, nullable: The latest trade in this market; null when none is in the history window.
        - `closes_at` string, date-time, nullable
        - `kalshi_url` string, uri
      - `closed` WatchClosed[]: Up to 100 with a known close time, latest close first. Without since, the most recent (a settled market whose time is not known goes by its last trade). With since and more than 100 after it, the 100 right after since, and data.as_of stops at them so the next poll continues there (closed_truncated says so); settled markets whose settlement time is not known follow, up to 100, most recently traded first.
        - `ticker` string
        - `event_ticker` string
        - `side` 'YES' | 'NO' | 'null', nullable: The side held until the position was sold. null for a settled market: the side held at settlement is not in the trade history.
        - `closed_at` string, date-time, nullable: sold: the trade that closed it. settled: when the market settled; null when that time is not known.
        - `reason` 'sold' | 'settled': sold: the trader traded out. settled: the market settled (it may have been sold before that; the trade history cannot tell).
      - `changes` WatchChange[]: Up to 100 trades, listed newest first. Without since, the newest 100. With since and more than 100 after it, the 100 right after since, and data.as_of stops at them so the next poll continues there (changes_truncated says so).
        - `id` string: The trade, the same in every answer: de-duplicate by it when polling. The second named trader on a trade between two public traders has an id ending in `:maker`.
        - `at` string, date-time
        - `ticker` string
        - `side` 'YES' | 'NO'
        - `action` 'opened' | 'added' | 'reduced' | 'closed' | 'flipped' | 'null', nullable: What the trade did to the position: opened (from flat), added, reduced, closed (to flat) or flipped (to the other side). null in a settled market the trader no longer holds, where the position before settlement is not known; in a market the holdings read did not reach (positions_complete false); and in a market traded again while it was read (that trade comes in the next answer).
        - `contracts` number
        - `price_cents` number: The price of `side` in cents, to 0.01.
        - `position_after` number, nullable: The position right after this trade, signed: YES positive, NO negative, 0 flat. null where action is null.
  - `meta` Meta, required
    - `generated_at` string, date-time
    - `definition` string
    - `verification` string
    - `docs` string, uri
    - `attribution` string
  - `hints` Hints, required
    - `tip` string
    - `next_steps` object[]
      - `label` string
      - `url` string, uri
      - `auth` 'api_key'
    - `similar` SettledWin[]
      - `ticker` string
      - `title` string
      - `outcome` string: Kalshi's short outcome label; empty for plain Yes/No markets.
      - `category` string
      - `category_key` 'politics' | 'elections' | 'sports' | 'entertainment' | 'economics' | 'financials' | 'crypto' | 'weather' | 'world' | 'scitech' | 'companies' | 'health' | 'social' | 'transportation' | 'mentions' | 'exotics' | 'other'
      - `series_ticker` string
      - `event_ticker` string
      - `result` 'yes' | 'no'
      - `settled_at` string, date-time
      - `whale_count` integer
      - `dissent_count` integer
      - `consensus_side` 'YES' | 'NO'
      - `consensus_pct` number
      - `net_profit_usd` number
      - `winners_profit_usd` number
      - `whales` SettledWhale[]
        - `nickname` string
        - `side` 'YES' | 'NO'
        - `profit_usd` number
      - `url` string, uri
      - `kalshi_url` string, uri

## Other responses

- `400`: Invalid parameter (`error.param` names it) or invalid cursor.
- `401`: Missing, malformed, unknown or revoked API key.
- `403`: The plan on this account has no API access (`error.upgrade_url`).
- `429`: Daily quota reached; `Retry-After` and `error.resets_at` say when it resets.
- `503`: Temporarily unavailable; retry shortly. The quota unit is given back, up to a daily refund budget.

---

[API](https://skmtc.dev/kalshispy/apis/kalshispy-api.md) · [All operations](https://skmtc.dev/kalshispy/apis/kalshispy-api/llms.txt) · [OpenAPI document](https://skmtc.dev/kalshispy/apis/kalshispy-api/revisions/5f483277dadc?raw)
