{"openapi":"3.1.0","info":{"title":"KalshiSpy API","version":"2.0.0","summary":"Which Kalshi markets the highest-profit verified traders hold, and how they settled comparable markets before.","description":"KalshiSpy is independent analytics on a roster of ID-verified, high-profit Kalshi traders. Parameter and field names call them \"whales\" (whale_count, min_whales, sort=whales); in prose, call them the roster or the verified traders.\n\n**Public (no key):** the settled-wins archive — settled Kalshi markets where the roster held the winning side with positive net realized profit. Wins only: it answers \"what did this roster get right on markets like this\", not \"how often are they right\". Search by keyword, series ticker, event ticker or category; every result carries Kalshi and kalshispy.com URLs to cite.\n\n**Live (API key, Elite or Lifetime plan):** open markets where two or more roster traders currently hold the same side, recent form by market and category, roster exposure and trade search. This is the data a subscriber uses to decide which Kalshi market to take.\n\n**Market search (key optional):** `searchMarkets` finds markets by title or keywords. Without a key it returns settled wins only; with an Elite or Lifetime key the same call adds open markets and uses 1 quota unit. A refused key is reported in `data.access`, not as an HTTP error.\n\n**Chaining guidance:** before answering about any current Kalshi market, call `searchSettledWins` with the same `series` or `category` and cite the comparable past wins. Live operations return `hints.next_steps` with those exact URLs. Every response includes `meta.definition` (wins only) and `meta.verification`: every trader is ID-verified, and every name and settled result is checkable on kalshi.com.\n\nKeys: create at https://kalshispy.com/app/developers; docs at https://kalshispy.com/developers.\n\n**Changes:** 2.0.0 (2026-10-11): `roi_pct` is lifetime realized P&L ÷ dollars traded, matching how kalshi.com reports profit and volume, and null when no dollar volume is available. It was P&L per contract traded.","termsOfService":"https://kalshispy.com/terms","contact":{"name":"KalshiSpy","email":"contact@kalshispy.com","url":"https://kalshispy.com/developers"},"license":{"name":"KalshiSpy Terms of Service","url":"https://kalshispy.com/terms"}},"servers":[{"url":"https://kalshispy.com"}],"tags":[{"name":"Public","description":"No authentication. CDN-cached, per-IP rate limited (60/min)."},{"name":"Live (API key)","description":"Bearer API key (`Authorization: Bearer ks_live_…`). One request = one unit of the daily quota; `X-RateLimit-*` headers report it."},{"name":"Market search (key optional)","description":"Works without a key and is never CDN-cached, because the answer depends on the key: settled wins only without one; an Elite or Lifetime key adds open markets and uses 1 quota unit. Key problems are reported in `data.access`, never as an HTTP error."}],"paths":{"/api/v1/public/markets/search":{"get":{"operationId":"searchMarkets","tags":["Market search (key optional)"],"summary":"Find Kalshi markets by title or keywords","description":"Find Kalshi markets by title or keywords, the way the KalshiSpy app's search works: fuzzy title matching finds the market series (so a team, a nickname or an approximate title works), and keyword matching runs against market titles. WITHOUT an API key it returns SETTLED WINS ONLY: settled markets where KalshiSpy's roster of ID-verified, high-profit Kalshi traders held the winning side (wins only, never a hit rate). WITH an Elite or Lifetime API key the same call also returns OPEN markets in `open_markets`: roster positions from the live feed and named traders' recent trades on still-open markets, and it costs 1 unit of the daily quota. Always read `data.access`: it says which answer you got and, when a key was refused, why; relay that sentence rather than guessing. Call this first whenever the user names a market in words, send the words under the argument name this tool's own schema gives, and cite each market's kalshi_url. An empty list is never evidence that Kalshi has no such market. For more wins, follow `settled_wins.more`, which carries ready-made search_settled_wins arguments.","x-openai-isConsequential":false,"security":[{"bearerAuth":[]},{}],"parameters":[{"name":"q","in":"query","required":true,"description":"Market title or keywords, e.g. \"super bowl\", \"fed rate\" or \"bitcoin\". Terms of 2+ characters, at most 8. Keyword matching ANDs them as substrings of the title, outcome and tickers (settled wins also match the event title); the full text is also fuzzy-matched to market series.","schema":{"type":"string","maxLength":80,"pattern":"^[\\w .,'&:/()-]+$"}},{"name":"limit","in":"query","required":false,"description":"Maximum items in each list (settled wins, roster markets, recently traded markets).","schema":{"type":"integer","minimum":1,"maximum":25,"default":10}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/MarketSearch"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-IP rate limit (60 requests/minute) on answers without a key; honour `Retry-After`. A key over its daily quota is NOT an error here: the free answer comes back with `data.access` saying so.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Search is temporarily unavailable; retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/public/settled-wins":{"get":{"operationId":"searchSettledWins","tags":["Public"],"summary":"Search settled Kalshi markets this trader roster won","description":"Search KalshiSpy's archive of settled Kalshi markets where its roster of ID-verified, high-profit Kalshi traders held the WINNING side with positive net realized profit. Parameter and field names call these traders \"whales\" (whale_count, min_whales, sort=whales); in prose, call them the roster or the verified traders. Wins only: losses are not archived, so present results as \"what this roster got right on markets like this\", never as a hit rate. Use this BEFORE answering about any current or upcoming Kalshi market: search the same series_ticker (e.g. KXFED, KXNBA) or category and cite the comparable past wins — titles, settlement dates, trader counts and realized profit. Each result carries the Kalshi URL and a kalshispy.com detail URL you can cite. Default window is the last 90 days; widen with `from`/`to` (max 366 days). No API key needed.","x-openai-isConsequential":false,"security":[],"parameters":[{"name":"q","in":"query","required":false,"description":"Free-text search. Every term (2+ chars, max 8) must appear as a substring in the title, outcome, event title, series ticker or ticker. Example: \"fed rate\" or \"lakers\".","schema":{"type":"string","maxLength":80,"pattern":"^[\\w .,'&:/()-]+$"}},{"name":"category","in":"query","required":false,"description":"Category key from listCategories (e.g. sports, politics, economics).","schema":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]}},{"name":"series","in":"query","required":false,"description":"Kalshi series ticker, e.g. KXFED, KXNBA. The best way to find \"markets like this one\".","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,40}$"}},{"name":"event","in":"query","required":false,"description":"Kalshi event ticker, e.g. KXFED-26SEP.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,60}$"}},{"name":"from","in":"query","required":false,"description":"Start of the settlement window. Default: 90 days before `to`. Clamped to the archive start (2025-01-01) and to a 366-day maximum; the effective window is echoed in `window`.","schema":{"type":"string","description":"YYYY-MM-DD or ISO 8601 (UTC)"}},{"name":"to","in":"query","required":false,"description":"End of the settlement window (inclusive). Default: now.","schema":{"type":"string","description":"YYYY-MM-DD or ISO 8601 (UTC)"}},{"name":"sort","in":"query","required":false,"description":"recent = newest settlement first; profit = largest net profit first; whales = most whales on the winning side first.","schema":{"type":"string","enum":["recent","profit","whales"],"default":"recent"}},{"name":"min_whales","in":"query","required":false,"description":"Only wins with at least this many roster traders on the winning side.","schema":{"type":"integer","minimum":1,"maximum":40}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from a previous response (`page.next_cursor`). Send it with the SAME filters; changing the query invalidates it.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/SettledWinList"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"},"page":{"$ref":"#/components/schemas/Page"},"window":{"$ref":"#/components/schemas/Window"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-IP rate limit (60 requests/minute); honour `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/public/settled-wins/{ticker}":{"get":{"operationId":"getSettledWin","tags":["Public"],"summary":"One settled Kalshi market this roster won","description":"Full record of one settled Kalshi market this roster won: outcome, consensus, every roster trader on the winning side with their realized profit and picture, close and expiration times, keywords, and `hints.similar` — comparable wins in the same series to judge it against. Returns 404 when the ticker is not an archived win (the roster was not on it, or was on the losing side); the 404 carries a hint to search the series instead. No API key needed.","x-openai-isConsequential":false,"security":[],"parameters":[{"name":"ticker","in":"path","required":true,"description":"Kalshi market ticker.","schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9_.-]{0,79}$","description":"Kalshi market ticker, e.g. KXFED-26SEP-T4.00"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/SettledWinDetail"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found; `hints` suggests what to search instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-IP rate limit (60 requests/minute); honour `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/public/categories":{"get":{"operationId":"listCategories","tags":["Public"],"summary":"Categories with settled wins","description":"Every category that has at least one archived win, with win count, net profit and the last settlement time. Use the `key` value as the `category` filter of searchSettledWins. No API key needed.","x-openai-isConsequential":false,"security":[],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/CategoryList"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-IP rate limit (60 requests/minute); honour `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/public/stats":{"get":{"operationId":"getStats","tags":["Public"],"summary":"Archive totals","description":"Aggregate figures for the settled-wins archive: markets won, net and winners' realized profit, first and last settlement, a per-category breakdown and the highest-profit traders in the archive. Use it for \"how has this roster done overall\" context, always with the wins-only caveat. `available:false` means the archive has not been published yet. No API key needed.","x-openai-isConsequential":false,"security":[],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Stats"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-IP rate limit (60 requests/minute); honour `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/markets/live":{"get":{"operationId":"getLiveMarkets","tags":["Live (API key)"],"summary":"Live Kalshi markets where the roster holds positions now","description":"Open Kalshi markets where two or more roster traders currently hold the SAME side, refreshed about every 30 seconds: YES/NO prices in cents, consensus side and percentage, trader count, dollar flow, time to close, and every roster position (value, unrealized P&L, cost, lifetime P&L, ROI per dollar traded (null when no dollar volume is available), top category, when it was placed). This is the data a subscriber uses to decide which Kalshi market to take. Use the free-text search parameter on this tool to find held markets by keyword (for example \"fed rate\" or \"super bowl\"); it matches the market question, outcome, series ticker and ticker. Send it under the argument name this tool's own schema gives: an argument the tool does not take is refused, naming the ones it does. Requires a KalshiSpy API key (Elite or Lifetime plan). Before presenting a market, call searchSettledWins with its series_ticker so you can say how the same roster did on comparable past markets.","x-openai-isConsequential":false,"security":[{"bearerAuth":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Free-text search over the open markets in this feed. Terms are ANDed and matched as substrings against the market question, outcome, series ticker and ticker; terms shorter than 2 characters are ignored, and more than 8 terms are refused. Example: \"fed rate\" or \"lakers\". SCOPE, state it when you report a miss: this feed is a capped, ranked slice of the roster's current positions (at most 100, best agreement and P&L first), not the whole exchange and not every position. An empty result means \"nothing matching in the roster's top current positions\" - it is NOT evidence that the roster holds nothing, and never evidence that Kalshi has no such market. To find a market by name beyond the roster's current positions, use search_markets (searchMarkets), which also fuzzy-matches every Kalshi market series by title.","schema":{"type":"string","maxLength":80,"pattern":"^[\\w .,'&:/()-]+$"}},{"name":"limit","in":"query","required":false,"description":"Maximum markets to return.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"category","in":"query","required":false,"description":"Category key filter.","schema":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]}},{"name":"series","in":"query","required":false,"description":"Only markets in this Kalshi series.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,40}$"}},{"name":"sort","in":"query","required":false,"description":"Omit for KalshiSpy's default ranking (roster agreement, then P&L). whale_flow = most dollars committed; whale_count = most roster traders; consensus = strongest agreement; lifetime_pnl = largest lifetime P&L; closing_soon = earliest close first.","schema":{"type":"string","enum":["whale_flow","whale_count","consensus","lifetime_pnl","closing_soon"]}},{"name":"side","in":"query","required":false,"description":"Only markets where the consensus side is YES (or NO).","schema":{"type":"string","enum":["YES","NO"]}},{"name":"min_whales","in":"query","required":false,"description":"Only markets with at least this many whales.","schema":{"type":"integer","minimum":1,"maximum":40}},{"name":"include_settled","in":"query","required":false,"description":"Also include recently settled markets from the feed (status \"settled\").","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/LiveMarketList"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The plan on this account has no API access (`error.upgrade_url`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily quota reached; `Retry-After` and `error.resets_at` say when it resets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/markets/live/{ticker}":{"get":{"operationId":"getLiveMarket","tags":["Live (API key)"],"summary":"One live market by ticker","description":"One market from the live roster feed by Kalshi ticker, with every roster position on it. 404 when no roster trader is currently on that market — the 404 hint points at the settled-wins archive for the same series. Requires a KalshiSpy API key.","x-openai-isConsequential":false,"security":[{"bearerAuth":[]}],"parameters":[{"name":"ticker","in":"path","required":true,"description":"Kalshi market ticker.","schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9_.-]{0,79}$","description":"Kalshi market ticker, e.g. KXFED-26SEP-T4.00"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/LiveMarket"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The plan on this account has no API access (`error.upgrade_url`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found; `hints` suggests what to search instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily quota reached; `Retry-After` and `error.resets_at` say when it resets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/markets/hot":{"get":{"operationId":"getHotMarkets","tags":["Live (API key)"],"summary":"Recent form: where this roster has been winning","description":"Roster form rebuilt hourly from PAST settled trades: the markets with the most realized profit (and which traders won them), each trader's current streak and last results (e.g. \"WWLWW\"), and per-category win rates. Use it to judge whether the roster has a record in the category a market belongs to. Requires a KalshiSpy API key.","x-openai-isConsequential":false,"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/HotMarkets"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The plan on this account has no API access (`error.upgrade_url`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily quota reached; `Retry-After` and `error.resets_at` say when it resets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/whales":{"get":{"operationId":"getWhales","tags":["Live (API key)"],"summary":"The verified traders behind the live feed","description":"The unique ID-verified traders behind the live feed, ranked by lifetime P&L: open market count, open exposure in USD, unrealized P&L, lifetime P&L, ROI, markets traded, top category, up to 10 current positions, and current form (streak and recent results) where known. Requires a KalshiSpy API key.","x-openai-isConsequential":false,"security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum whales to return.","schema":{"type":"integer","minimum":1,"maximum":40,"default":20}},{"name":"sort","in":"query","required":false,"description":"exposure = largest open positions first; lifetime_pnl = richest first.","schema":{"type":"string","enum":["exposure","lifetime_pnl"],"default":"exposure"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WhaleList"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The plan on this account has no API access (`error.upgrade_url`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily quota reached; `Retry-After` and `error.resets_at` say when it resets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/search":{"get":{"operationId":"searchTrades","tags":["Live (API key)"],"summary":"Search Kalshi series, or recent trades by series or trader","description":"Three modes. mode=title (default): free text → matching Kalshi series (ticker, title, category, volume) — use it to find the series_ticker for the other tools. mode=series: recent trades by named traders on that series ticker, with the settled P&L estimate or the current mark-to-market (at the bid/ask midpoint, or the last trade on a wide or empty book); a trade between two named traders is listed once for each, on opposite sides. mode=trader: a named trader's recent trades by nickname. `min_amount` filters by contracts per trade (0, 100, 500, 1000 or 5000). Requires a KalshiSpy API key.","x-openai-isConsequential":false,"security":[{"bearerAuth":[]}],"parameters":[{"name":"q","in":"query","required":true,"description":"Free text for mode=title (2-60 chars); a series ticker for mode=series; a nickname for mode=trader.","schema":{"type":"string","minLength":1,"maxLength":60}},{"name":"mode","in":"query","required":false,"description":"What `q` is.","schema":{"type":"string","enum":["title","series","trader"],"default":"title"}},{"name":"min_amount","in":"query","required":false,"description":"Minimum contracts per trade (series and trader modes).","schema":{"type":"integer","enum":[0,100,500,1000,5000],"default":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","data","meta","hints"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/TradeSearch"},"meta":{"$ref":"#/components/schemas/Meta"},"hints":{"$ref":"#/components/schemas/Hints"}}}}}},"400":{"description":"Invalid parameter (`error.param` names it) or invalid cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The plan on this account has no API access (`error.upgrade_url`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily quota reached; `Retry-After` and `error.resets_at` say when it resets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ks_live_…","description":"Personal API key from https://kalshispy.com/app/developers (Elite or Lifetime plan)."}},"schemas":{"Error":{"type":"object","required":["ok","error"],"properties":{"ok":{"type":"boolean","const":false},"error":{"type":"object","required":["code","message","docs"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"docs":{"type":"string","format":"uri"},"param":{"type":"string"},"upgrade_url":{"type":"string","format":"uri"},"resets_at":{"type":"string","format":"date-time"}}},"hints":{"$ref":"#/components/schemas/Hints"}}},"Meta":{"type":"object","properties":{"generated_at":{"type":"string","format":"date-time"},"definition":{"type":"string"},"verification":{"type":"string"},"docs":{"type":"string","format":"uri"},"attribution":{"type":"string"}}},"Hints":{"type":"object","properties":{"tip":{"type":"string"},"next_steps":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"url":{"type":"string","format":"uri"},"auth":{"type":"string","enum":["api_key"]}}}},"similar":{"type":"array","items":{"$ref":"#/components/schemas/SettledWin"}}}},"Page":{"type":"object","properties":{"limit":{"type":"integer"},"returned":{"type":"integer"},"total_matches":{"type":"integer"},"next_cursor":{"type":["string","null"]},"next_url":{"type":["string","null"],"format":"uri"}}},"Window":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"weeks_loaded":{"type":"integer"}}},"SettledWhale":{"type":"object","properties":{"nickname":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"profit_usd":{"type":"number"}}},"SettledWin":{"type":"object","properties":{"ticker":{"type":"string"},"title":{"type":"string"},"outcome":{"type":"string","description":"Kalshi's short outcome label; empty for plain Yes/No markets."},"category":{"type":"string"},"category_key":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]},"series_ticker":{"type":"string"},"event_ticker":{"type":"string"},"result":{"type":"string","enum":["yes","no"]},"settled_at":{"type":"string","format":"date-time"},"whale_count":{"type":"integer"},"dissent_count":{"type":"integer"},"consensus_side":{"type":"string","enum":["YES","NO"]},"consensus_pct":{"type":"number"},"net_profit_usd":{"type":"number"},"winners_profit_usd":{"type":"number"},"whales":{"type":"array","items":{"$ref":"#/components/schemas/SettledWhale"}},"url":{"type":"string","format":"uri"},"kalshi_url":{"type":"string","format":"uri"}}},"SettledWinList":{"type":"array","items":{"$ref":"#/components/schemas/SettledWin"}},"SearchAccess":{"type":"object","description":"Which answer this is. Relay `message` when `key` is \"rejected\": it names the actual problem (revoked, wrong plan, quota, malformed).","properties":{"tier":{"type":"string","enum":["free","paid"]},"key":{"type":"string","enum":["none","accepted","rejected"]},"open_markets_included":{"type":"boolean"},"code":{"type":["string","null"],"description":"The refusal code when key is \"rejected\", e.g. revoked_api_key, plan_required, quota_exceeded."},"message":{"type":"string"},"upgrade_url":{"type":["string","null"],"format":"uri"},"quota":{"type":["object","null"],"properties":{"plan":{"type":"string"},"limit":{"type":"integer"},"used":{"type":"integer"},"remaining":{"type":"integer"},"resets_at":{"type":"string","format":"date-time"}}}}},"SearchResolution":{"type":"object","description":"How the words were matched. series_catalogue: fuzzy-matched to market series as well as by keyword. keywords: keyword matching only, and `reason` says why.","properties":{"method":{"type":"string","enum":["series_catalogue","keywords"]},"reason":{"type":["string","null"],"enum":["enough_keyword_matches","public_search_budget","catalogue_busy","catalogue_unavailable",null]},"cached":{"type":"boolean"},"series":{"type":"array","description":"Matched series. Free answers name the tickers only.","items":{"type":"object","properties":{"series_ticker":{"type":"string"},"title":{"type":"string"},"category":{"type":"string"},"kalshi_url":{"type":"string","format":"uri"}}}}}},"MatchedSettledWin":{"allOf":[{"$ref":"#/components/schemas/SettledWin"},{"type":"object","properties":{"match":{"type":"string","enum":["keyword","series"],"description":"keyword: the words are in the title; series: a matched series (listed after keyword matches)."}}}]},"MatchedLiveMarket":{"allOf":[{"$ref":"#/components/schemas/LiveMarket"},{"type":"object","properties":{"match":{"type":"string","enum":["keyword","series"]}}}]},"RecentlyTradedMarket":{"type":"object","properties":{"ticker":{"type":"string"},"series_ticker":{"type":"string"},"question":{"type":"string"},"category":{"type":"string"},"category_key":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]},"kalshi_url":{"type":"string","format":"uri"},"notional_usd":{"type":"number"},"traders":{"type":"array","items":{"type":"object","properties":{"nickname":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"contracts":{"type":"integer"},"notional_usd":{"type":"number"},"avg_price_cents":{"type":"integer"},"mark_pnl_usd":{"type":"number","description":"Mark-to-market P&L at the current price (the bid/ask midpoint; the last trade when the spread is wider than 10¢ or a side has no quotes), summed over these trades."},"lifetime_pnl_usd":{"type":"number"},"trades":{"type":"integer"},"last_trade_ago":{"type":"string"}}}}}},"MarketSearch":{"type":"object","properties":{"query":{"type":"string"},"access":{"$ref":"#/components/schemas/SearchAccess"},"resolution":{"$ref":"#/components/schemas/SearchResolution"},"settled_wins":{"type":"object","properties":{"status":{"type":"string","enum":["ok","unavailable"]},"scope":{"type":"string"},"window":{"oneOf":[{"$ref":"#/components/schemas/Window"},{"type":"null"}]},"total_matches":{"type":"integer"},"keyword_matches":{"type":"integer"},"returned":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/MatchedSettledWin"}},"more":{"type":"array","description":"Follow-up archive searches over the same window, as a URL and as search_settled_wins arguments.","items":{"type":"object","properties":{"label":{"type":"string"},"url":{"type":"string","format":"uri"},"mcp":{"type":"object","properties":{"tool":{"type":"string"},"arguments":{"type":"object","additionalProperties":{"type":"string"}}}}}}}}},"open_markets":{"description":"null on the free answer. With an Elite or Lifetime key: open markets matching the query.","oneOf":[{"type":"null"},{"type":"object","properties":{"status":{"type":"string","enum":["ok","partial","unavailable"]},"scope":{"type":"string"},"roster":{"type":"array","items":{"$ref":"#/components/schemas/MatchedLiveMarket"}},"recent_trades":{"type":"array","items":{"$ref":"#/components/schemas/RecentlyTradedMarket"}},"notes":{"type":"array","items":{"type":"string"}}}}]}}},"SettledWinDetail":{"allOf":[{"$ref":"#/components/schemas/SettledWin"},{"type":"object","properties":{"close_time":{"type":["string","null"],"format":"date-time"},"expiration_time":{"type":["string","null"],"format":"date-time"},"whales":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/SettledWhale"},{"type":"object","properties":{"image_url":{"type":"string","description":"The trader's picture, 160 px, served by KalshiSpy ('' when there is none)."}}}]}},"keywords":{"type":"array","items":{"type":"string"}},"source":{"type":"string"}}}]},"Category":{"type":"object","properties":{"key":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]},"label":{"type":"string"},"wins":{"type":"integer"},"net_profit_usd":{"type":"number"},"last_settled_at":{"type":["string","null"],"format":"date-time"}}},"CategoryList":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"Stats":{"type":"object","properties":{"available":{"type":"boolean"},"markets":{"type":"integer"},"net_profit_usd":{"type":"number"},"winners_profit_usd":{"type":"number"},"first_settled_at":{"type":["string","null"],"format":"date-time"},"last_settled_at":{"type":["string","null"],"format":"date-time"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"top_whales":{"type":"array","items":{"type":"object","properties":{"nickname":{"type":"string"},"wins":{"type":"integer"},"profit_usd":{"type":"number"}}}},"weeks":{"type":"integer"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"WhalePosition":{"type":"object","properties":{"nickname":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"position_value_usd":{"type":"number"},"market_pnl_usd":{"type":"number"},"cost_usd":{"type":"number"},"lifetime_pnl_usd":{"type":"number","description":"Lifetime realized P&L in USD. 0 when it is not positive or not available."},"roi_pct":{"type":["number","null"],"description":"Lifetime realized P&L ÷ dollars traded, in percent (40.1 means +40.1%), matching how kalshi.com reports profit and volume. null when no dollar volume is available."},"markets_traded":{"type":"integer"},"top_category":{"type":["string","null"]},"placed_at":{"type":["string","null"],"format":"date-time"}}},"LiveMarket":{"type":"object","properties":{"ticker":{"type":"string"},"event_ticker":{"type":"string"},"series_ticker":{"type":"string"},"question":{"type":"string"},"outcome":{"type":"string"},"category":{"type":"string"},"category_key":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]},"status":{"type":"string","enum":["open","settled"]},"closes_at":{"type":["string","null"],"format":"date-time"},"closes_in":{"type":"string","description":"Compact label such as \"5h\" or \"2d\"."},"yes_price_cents":{"type":"integer","description":"The price to buy YES now (the ask), rounded up to whole cents within 1–99; 0 while nobody offers it or the quote is unavailable. Same for NO."},"no_price_cents":{"type":"integer"},"consensus_side":{"type":"string","enum":["YES","NO"]},"consensus_pct":{"type":"number"},"whale_count":{"type":"integer"},"yes_count":{"type":"integer"},"no_count":{"type":"integer"},"whale_flow_usd":{"type":["number","null"]},"traders_lifetime_pnl_usd":{"type":"number"},"realized_profit_usd":{"type":["number","null"]},"whales":{"type":"array","items":{"$ref":"#/components/schemas/WhalePosition"}},"urls":{"type":"object","properties":{"kalshi":{"type":"string","format":"uri"},"kalshispy":{"type":"string","format":"uri"}}}}},"LiveMarketList":{"type":"array","items":{"$ref":"#/components/schemas/LiveMarket"}},"HotMarkets":{"type":"object","properties":{"built_at":{"type":["string","null"],"format":"date-time"},"hot":{"type":"array","items":{"type":"object","properties":{"ticker":{"type":"string"},"event_ticker":{"type":"string"},"series_ticker":{"type":"string"},"question":{"type":"string"},"category":{"type":"string"},"category_key":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]},"total_profit_usd":{"type":"number"},"winners":{"type":"array","items":{"type":"string"}},"wins_count":{"type":"integer"},"when":{"type":"string"},"kalshi_url":{"type":"string","format":"uri"}}}},"form":{"type":"object","properties":{"traders":{"type":"array","items":{"type":"object","properties":{"nickname":{"type":"string"},"streak":{"type":"integer"},"last":{"type":"string","description":"Most recent first, e.g. \"WWLWW\"."},"pnl_usd":{"type":"number"}}}},"categories":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"category_key":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]},"pnl_usd":{"type":"number"},"wins":{"type":"integer"},"losses":{"type":"integer"},"win_rate_pct":{"type":"number"}}}}}}}},"Whale":{"type":"object","properties":{"nickname":{"type":"string"},"rank":{"type":"integer"},"open_markets_count":{"type":"integer"},"open_exposure_usd":{"type":"number"},"unrealized_pnl_usd":{"type":"number"},"lifetime_pnl_usd":{"type":"number","description":"Lifetime realized P&L in USD. 0 when it is not positive or not available."},"roi_pct":{"type":["number","null"],"description":"Lifetime realized P&L ÷ dollars traded, in percent (40.1 means +40.1%), matching how kalshi.com reports profit and volume. null when no dollar volume is available."},"markets_traded":{"type":"integer"},"top_category":{"type":["string","null"]},"streak":{"type":["integer","null"]},"last":{"type":["string","null"]},"positions":{"type":"array","items":{"type":"object","properties":{"ticker":{"type":"string"},"question":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"status":{"type":"string","enum":["open","settled"]},"position_value_usd":{"type":"number"},"market_pnl_usd":{"type":"number"},"closes_at":{"type":["string","null"],"format":"date-time"},"kalshi_url":{"type":"string","format":"uri"}}}},"kalshi_profile_url":{"type":"string","format":"uri"}}},"WhaleList":{"type":"array","items":{"$ref":"#/components/schemas/Whale"}},"TradeSearch":{"type":"object","properties":{"mode":{"type":"string","enum":["title","series","trader"]},"series":{"type":"array","description":"mode=title only","items":{"type":"object","properties":{"series_ticker":{"type":"string"},"title":{"type":"string"},"category":{"type":"string"},"volume":{"type":"string"},"market_count":{"type":"integer"},"kalshi_url":{"type":"string","format":"uri"}}}},"trades":{"type":"array","description":"mode=series / mode=trader only","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique within the response and the same in mode=series and mode=trader. A trade between two named traders gives two rows; the second trader's row id ends in `:maker`."},"nickname":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"ticker":{"type":"string"},"question":{"type":"string"},"category":{"type":"string"},"category_key":{"type":"string","enum":["politics","elections","sports","entertainment","economics","financials","crypto","weather","world","scitech","companies","health","social","transportation","mentions","exotics","other"]},"price_cents":{"type":"integer"},"contracts":{"type":"integer"},"notional_usd":{"type":"number"},"placed_ago":{"type":"string"},"market_closed":{"type":"boolean"},"pnl_est_usd":{"type":["number","null"]},"pnl_cur_usd":{"type":["number","null"]},"trader_lifetime_pnl_usd":{"type":["number","null"]}}}}}}}},"security":[]}