{"openapi":"3.0.3","info":{"title":"Kalshi Sports Market Data API","version":"2.0.0","description":"Real-time sports prediction market data sourced from Kalshi. Gzip-compressed, Redis-cached, structured with Pino logging.\n\n## Key Concepts\n- **Sport** — Top-level grouping (NBA, MLB, NFL, NHL)\n- **Event** — A game/matchup (e.g. \"Brooklyn at Toronto\")\n- **Market** — A prediction within an event (e.g. \"Winner?\"). Each team gets its own market.\n- **Contract** — YES/NO side of a market. Prices are in dollars (0.00–1.00). A YES price of 0.60 = 60% implied probability.\n\n## Performance\n- All responses are gzip-compressed when `Accept-Encoding: gzip` is sent.\n- Read endpoints are Redis-cached (3–10s TTL). The `X-Cache` header shows HIT or MISS.\n- `X-Response-Time` header on every response.\n- `meta.took_ms` inside every JSON body.\n\n## WebSocket\nReal-time streaming available at `ws://host:4000/ws/v1`. See the `/api/docs` endpoint for full protocol documentation.","contact":{"name":"Kalshi NBA Viewer"},"license":{"name":"MIT"}},"servers":[{"url":"http://localhost:4000","description":"Local development"}],"tags":[{"name":"Health","description":"Service health check"},{"name":"Sports","description":"Sport-level summaries"},{"name":"Prices","description":"Low-latency flat price feeds"},{"name":"Search","description":"Fuzzy text search across events and markets"},{"name":"Events","description":"Game/matchup data with nested markets"},{"name":"Markets","description":"Prediction markets with nested contracts"},{"name":"Contracts","description":"Individual YES/NO contract data and price history"}],"paths":{"/health":{"get":{"tags":["Health"],"summary":"Service health check","operationId":"getHealth","responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"timestamp":{"type":"string","format":"date-time"},"meta":{"$ref":"#/components/schemas/Meta"}}}}}}}}},"/api/sports":{"get":{"tags":["Sports"],"summary":"List sports with market and event counts","operationId":"listSports","responses":{"200":{"description":"Array of sports with counts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SportSummary"}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/prices":{"get":{"tags":["Prices"],"summary":"Ultra-slim flat price feed — lowest latency","description":"Returns one row per active contract with computed mid-price and spread. No nesting, no event data — designed for ticker displays and algorithmic consumers.","operationId":"listPrices","parameters":[{"$ref":"#/components/parameters/SportQuery"},{"name":"side","in":"query","schema":{"type":"string","enum":["YES","NO"]},"description":"Filter by contract side"}],"responses":{"200":{"description":"Flat array of contract prices","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PriceRow"}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/prices/summary":{"get":{"tags":["Prices"],"summary":"Game-level price summary with both team lines","description":"One row per game with home/away team lines including last, bid, ask, and mid prices.","operationId":"listPriceSummary","parameters":[{"$ref":"#/components/parameters/SportQuery"}],"responses":{"200":{"description":"Array of game summaries","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GameSummary"}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/search":{"get":{"tags":["Search"],"summary":"Fuzzy search events and markets","description":"Search by team name, event title, ticker, or market subtitle. Minimum 2 characters.","operationId":"search","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2},"description":"Search query (min 2 characters). Examples: `Boston`, `Lakers`, `KXNBAGAME`"}],"responses":{"200":{"description":"Matching events and markets","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"data":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SearchEvent"}},"markets":{"type":"array","items":{"$ref":"#/components/schemas/SearchMarket"}}}},"meta":{"type":"object","properties":{"event_count":{"type":"integer"},"market_count":{"type":"integer"},"cached":{"type":"boolean"},"took_ms":{"type":"number"}}}}}}}},"400":{"description":"Invalid query","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID_QUERY","message":"Query must be at least 2 characters"}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/events":{"get":{"tags":["Events"],"summary":"List events (games) with nested markets and contracts","operationId":"listEvents","parameters":[{"$ref":"#/components/parameters/SportQuery"},{"$ref":"#/components/parameters/StatusQuery"},{"$ref":"#/components/parameters/LimitQuery"},{"$ref":"#/components/parameters/OffsetQuery"}],"responses":{"200":{"description":"Paginated list of events","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"meta":{"$ref":"#/components/schemas/PaginatedMeta"}}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/events/{id}":{"get":{"tags":["Events"],"summary":"Get a single event with all markets","description":"Accepts a UUID or a Kalshi event ticker (e.g. `KXNBAGAME-26APR12BKNTOR`).","operationId":"getEvent","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Event UUID or Kalshi event ticker"}],"responses":{"200":{"description":"Event with nested markets and contracts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/markets":{"get":{"tags":["Markets"],"summary":"List markets with nested contracts","operationId":"listMarkets","parameters":[{"$ref":"#/components/parameters/SportQuery"},{"$ref":"#/components/parameters/StatusQuery"},{"$ref":"#/components/parameters/LimitQuery"},{"$ref":"#/components/parameters/OffsetQuery"}],"responses":{"200":{"description":"Paginated list of markets","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Market"}},"meta":{"$ref":"#/components/schemas/PaginatedMeta"}}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/markets/{id}":{"get":{"tags":["Markets"],"summary":"Get a single market with contracts","operationId":"getMarket","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Market UUID"}],"responses":{"200":{"description":"Market with nested contracts and event context","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDetail"}}}},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/contracts/{id}":{"get":{"tags":["Contracts"],"summary":"Get a single contract","operationId":"getContract","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Contract UUID"}],"responses":{"200":{"description":"Contract detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractDetail"}}}},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/contracts/{id}/price-history":{"get":{"tags":["Contracts"],"summary":"Get price history for a contract","operationId":"getContractPriceHistory","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Contract UUID"},{"name":"period","in":"query","schema":{"type":"string","enum":["1h","6h","24h","7d","30d"],"default":"24h"},"description":"Lookback period"}],"responses":{"200":{"description":"Array of price history records","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PriceHistoryRecord"}},"meta":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string"},"cached":{"type":"boolean"},"took_ms":{"type":"number"}}}}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"parameters":{"SportQuery":{"name":"sport","in":"query","schema":{"type":"string","enum":["NBA","MLB","NFL","NHL"]},"description":"Filter by sport (case-insensitive)"},"StatusQuery":{"name":"status","in":"query","schema":{"type":"string","enum":["open","closed","settled","scheduled"]},"description":"Filter by status"},"LimitQuery":{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":200},"description":"Number of results to return"},"OffsetQuery":{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Pagination offset"}},"schemas":{"Meta":{"type":"object","properties":{"count":{"type":"integer","description":"Number of items in data array"},"cached":{"type":"boolean","description":"Whether response was served from Redis cache"},"took_ms":{"type":"number","description":"Server processing time in milliseconds"}}},"PaginatedMeta":{"allOf":[{"$ref":"#/components/schemas/Meta"},{"type":"object","properties":{"total":{"type":"integer","description":"Total matching items for pagination"}}}]},"ErrorBody":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code"},"message":{"type":"string","description":"Human-readable error description"}}},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorBody"},"meta":{"$ref":"#/components/schemas/Meta"}}},"SportSummary":{"type":"object","properties":{"sport":{"type":"string","example":"NBA"},"market_count":{"type":"integer","example":30},"event_count":{"type":"integer","example":15}}},"PriceRow":{"type":"object","description":"Flat contract price — one row per active contract","properties":{"contract_id":{"type":"string","format":"uuid"},"market_id":{"type":"string","format":"uuid"},"event_id":{"type":"string","format":"uuid"},"symbol":{"type":"string","example":"KXNBAGAME-26APR12BKNTOR-TOR-YES"},"ticker":{"type":"string","example":"KXNBAGAME-26APR12BKNTOR-TOR"},"sport":{"type":"string","example":"NBA"},"team":{"type":"string","example":"Toronto"},"side":{"type":"string","enum":["YES","NO"]},"last":{"type":"number","nullable":true,"example":0.95,"description":"Last trade price (0.00–1.00)"},"bid":{"type":"number","nullable":true,"example":0.94,"description":"Best bid price"},"ask":{"type":"number","nullable":true,"example":0.95,"description":"Best ask price"},"mid":{"type":"number","nullable":true,"example":0.945,"description":"Mid-point of bid/ask"},"spread":{"type":"number","nullable":true,"example":0.01,"description":"Bid-ask spread"},"vol24h":{"type":"integer","example":64402,"description":"24-hour volume in contracts"},"oi":{"type":"integer","example":58432,"description":"Open interest"}}},"TeamLine":{"type":"object","properties":{"team":{"type":"string","example":"Charlotte"},"ticker":{"type":"string","example":"KXNBAGAME-26APR12CHANYK-CHA"},"last":{"type":"number","nullable":true,"example":0.73},"bid":{"type":"number","nullable":true,"example":0.73},"ask":{"type":"number","nullable":true,"example":0.74},"mid":{"type":"number","nullable":true,"example":0.735}}},"GameSummary":{"type":"object","description":"One row per game with both team lines","properties":{"event_id":{"type":"string","format":"uuid"},"external_id":{"type":"string","example":"KXNBAGAME-26APR12CHANYK"},"title":{"type":"string","example":"Charlotte at New York"},"sport":{"type":"string"},"home_team":{"type":"string"},"away_team":{"type":"string"},"starts_at":{"type":"string","format":"date-time","nullable":true},"lines":{"type":"array","items":{"$ref":"#/components/schemas/TeamLine"},"description":"One entry per team"}}},"ContractCompact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"symbol":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"last_price":{"type":"number","nullable":true},"best_bid":{"type":"number","nullable":true},"best_ask":{"type":"number","nullable":true},"volume_24h":{"type":"integer"},"open_interest":{"type":"integer"},"status":{"type":"string"}}},"ContractFull":{"allOf":[{"$ref":"#/components/schemas/ContractCompact"},{"type":"object","properties":{"market_id":{"type":"string","format":"uuid"},"settlement_value":{"type":"number","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}]},"ContractDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"market_id":{"type":"string","format":"uuid"},"symbol":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"last_price":{"type":"number","nullable":true},"best_bid":{"type":"number","nullable":true},"best_ask":{"type":"number","nullable":true},"volume_24h":{"type":"integer"},"open_interest":{"type":"integer"},"status":{"type":"string"},"settlement_value":{"type":"number","nullable":true},"market_title":{"type":"string"},"meta":{"$ref":"#/components/schemas/Meta"}}},"MarketCompact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_id":{"type":"string"},"title":{"type":"string"},"market_type":{"type":"string","example":"binary"},"status":{"type":"string","enum":["open","closed","settled"]},"yes_subtitle":{"type":"string","nullable":true},"no_subtitle":{"type":"string","nullable":true},"result":{"type":"string","nullable":true,"enum":["yes","no","void",null]},"settlement_price":{"type":"number","nullable":true,"description":"Settlement value in dollars (1.00 = YES wins, 0.00 = NO wins)"},"close_time":{"type":"string","format":"date-time","nullable":true},"contracts":{"type":"array","items":{"$ref":"#/components/schemas/ContractCompact"}}}},"Market":{"allOf":[{"$ref":"#/components/schemas/MarketCompact"},{"type":"object","properties":{"event_id":{"type":"string","format":"uuid"},"description":{"type":"string","nullable":true},"settlement_price":{"type":"number","nullable":true},"closes_at":{"type":"string","format":"date-time","nullable":true},"open_time":{"type":"string","format":"date-time","nullable":true},"close_time":{"type":"string","format":"date-time","nullable":true},"rules_primary":{"type":"string","nullable":true},"sport":{"type":"string"},"event_title":{"type":"string"},"home_team":{"type":"string","nullable":true},"away_team":{"type":"string","nullable":true},"game_starts_at":{"type":"string","format":"date-time","nullable":true},"league":{"type":"string","nullable":true},"game_status":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"contracts":{"type":"array","items":{"$ref":"#/components/schemas/ContractFull"}}}}]},"MarketDetail":{"description":"Single market view — same as Market but returned as top-level object (not inside data array)","$ref":"#/components/schemas/Market"},"Event":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_id":{"type":"string","example":"KXNBAGAME-26APR12ATLMIA"},"sport":{"type":"string"},"league":{"type":"string","nullable":true},"title":{"type":"string","example":"Atlanta at Miami"},"home_team":{"type":"string","nullable":true},"away_team":{"type":"string","nullable":true},"starts_at":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string","enum":["scheduled","open","closed","settled"],"description":"Derived from child market statuses"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"markets":{"type":"array","items":{"$ref":"#/components/schemas/MarketCompact"}}}},"SearchEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_id":{"type":"string"},"sport":{"type":"string"},"title":{"type":"string"},"home_team":{"type":"string","nullable":true},"away_team":{"type":"string","nullable":true},"starts_at":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string"},"market_count":{"type":"integer"},"lines":{"type":"array","items":{"type":"object","properties":{"team":{"type":"string"},"last":{"type":"number","nullable":true},"bid":{"type":"number","nullable":true},"ask":{"type":"number","nullable":true}}}}}},"SearchMarket":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"external_id":{"type":"string"},"title":{"type":"string"},"sport":{"type":"string"},"status":{"type":"string"},"yes_subtitle":{"type":"string","nullable":true},"event_title":{"type":"string"},"home_team":{"type":"string","nullable":true},"away_team":{"type":"string","nullable":true},"starts_at":{"type":"string","format":"date-time","nullable":true},"contracts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"symbol":{"type":"string"},"side":{"type":"string","enum":["YES","NO"]},"last":{"type":"number","nullable":true},"bid":{"type":"number","nullable":true},"ask":{"type":"number","nullable":true}}}}}},"PriceHistoryRecord":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"contract_id":{"type":"string","format":"uuid"},"price":{"type":"number","example":0.96},"bid_price":{"type":"number","nullable":true},"ask_price":{"type":"number","nullable":true},"volume":{"type":"integer"},"recorded_at":{"type":"string","format":"date-time"}}}},"responses":{"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"Resource 'abc' not found"},"meta":{"cached":false,"took_ms":1.2}}}}},"InternalError":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INTERNAL_ERROR","message":"An unexpected error occurred"},"meta":{"took_ms":0}}}}}}},"meta":{"took_ms":2.6}}