Get one market
One market by venue and market_id. Missing or hidden from the plan is 404; the response never says which. A venue the data policy blocks is 403 blocked, whether or not the market exists.
ApiKeyX-API-Key<token>Data endpoints. Format st_live__ (ADR-0012).
venue*stringmarket_id*stringMarket
application/json- response
block_reason_code*|Why fields are withheld: licence_undecided, licence_derived_only or geo_policy. Null when blocked is false.
blocked*booleanTrue when the data policy withholds some of this row's fields for this request. Those fields are null and block_reason_code says why.
category?|Venue category label when present.
close_at?|Time the market closed for trading, UTC.
date-timefirst_trade_at?|Time of the first known trade, UTC.
date-timelast_trade_at?|Time of the latest known trade, UTC.
date-timemarket_id*stringVenue-native market identifier.
open_at?|Time the market opened for trading, UTC.
date-timeoutcomes*array<>Selectable outcomes with labels and token ids.
quality_flags*array<string>Quality markers such as volume_quality_flagged.
question?|Market question text as published by the venue.
rules_hash?|Hash of rules_text used to detect rule changes. Null when the data policy withholds rules_text.
rules_text?|Full resolution rules text when available.
schema_version*stringData schema version for this row.
slug?|Short public slug when the venue publishes one.
source_kind*stringSource that supplied the market text.
"chain""venue_api""bulk_dataset"status*stringLife-cycle status of the market.
"open""closed""resolved""voided"updated_at*stringTime this row was last updated, UTC.
date-timevenue*stringVenue key that owns this market.
venue_event_id?|The venue's own grouping key for sibling markets, when it publishes one: for Polymarket the neg-risk market id of a neg-risk group, else the Gamma event id. Not a Skewtape matched event id.
curl -X GET 'https://api.skewtape.com/v1/markets/string/string'{ "block_reason_code": "string", "blocked": true, "category": "string", "close_at": "2019-08-24T14:15:22Z", "first_trade_at": "2019-08-24T14:15:22Z", "last_trade_at": "2019-08-24T14:15:22Z", "market_id": "string", "open_at": "2019-08-24T14:15:22Z", "outcomes": [ { "label": "string", "token_id": "string" } ], "quality_flags": [ "string" ], "question": "string", "rules_hash": "string", "rules_text": "string", "schema_version": "string", "slug": "string", "source_kind": "chain", "status": "open", "updated_at": "2019-08-24T14:15:22Z", "venue": "string", "venue_event_id": "string"}Powered by Kalshi Research
Live feed (WebSocket) GET
WebSocket upgrade (ADR-0013, ARCHITECTURE 10). Builder and Pro plans; the plans table says how many connections an account may hold (Builder 3, Pro 10, counted across all its keys). Not served by a generated handler: this operation documents the protocol. Authentication: the X-API-Key header on the upgrade, or the first message {"op":"auth","key":"st_live_..."} within 10 seconds. Messages from the client: {"op":"subscribe","topics":["markets","resolutions","trades","event_spread"], "venues":["kalshi"],"markets":[{"venue":"polymarket","market_id":"0x..."}], "events":["st_evt_00042"],"resume_from":123} replaces the subscription (topics required; the filters are ORed and optional; the events filter, matched event ids, narrows event_spread, whose rows belong to an event and not a venue, so the venue and market filters do not narrow them; it needs that topic: with other topics alone it is refused, and beside event_spread it leaves those topics to the venue and market filters, whole when there are none; a market filter cuts a trades_batch to its markets' fills); {"op":"ping"} answers {"op":"pong"} at once, even during a replay. markets, resolutions and trades need Builder or above, event_spread Pro; a plan that loses a topic during a connection is told (error topic_not_in_plan) and keeps its other topics. Trades (E15-T3) are fills from venue streams, one event per fill with the stored row's identity (venue, tx_hash, log_index) up to 400 a second per venue, the rest of the second folded into one trades_batch; the hourly walk stores the row afterwards, and a leader that takes over re-reads the last blocks, so dedupe by identity. event_spread is one approved matched event's fee-adjusted spread, at most one event per matched event per five seconds (FeedSpread). Right after subscribed, a subscription to event_spread receives the latest spread of each event it names as snapshot messages (op snapshot, FeedSnapshot): a state with no seq, never a point to resume from; the replay then carries the other topics and live spreads follow as events, so a replay returns the latest per event, never each tick. A subscription sent before the instance has read the log once is answered error not_ready: send it again. Subscribes sent while the connection is busy (a replay, a slow write) are not queued: the latest one is applied when the connection is free, and each earlier one that never ran is answered error superseded. Messages from the server, each with op: hello (connection_id, plan, the current seq, the replay window and the reconnect schedule), subscribed (what was accepted, replay_to, masked_venues), snapshot (one FeedSnapshot: the latest spread of a matched event, no seq), event (one FeedEvent: seq, topic, kind, venue, market_id, at, payload), resync (resume_from is older than the replay window: read the API for what you missed, live events follow), reconnect (sent at 55 minutes with resume_from; the connection closes at 59 minutes, before the 60-minute platform limit), error (code, message). Replay (D2): resume_from replays the stored events after that seq that match the subscription, then switches to live with no gap and no duplicate; a client keeps the last seq it saw. Every connection also receives the feed's own gap notices (topic feed, kind gap) when a venue stream reconnected: the stored data has no gap, so read the API for that window or wait for the next hourly run. Policy (ADR-0028): a subscription naming a venue the live_data policy blocks is refused (error venue_blocked); a masked venue's events ship with the listed fields null and blocked true. Close codes: 4000 reconnect (the age limit, or a registration that expired while the server could not heartbeat; both carry resume_from), 4001 unauthorized (also when the key is revoked during the connection: keys and plans are read again every few minutes), 4003 plan (no feed, or a topic the plan no longer covers), 4008 connection limit, 4009 slow consumer (the reason carries resume_from), 4029 too many failed key lookups, 4400 bad message, 1001 server restarting.
Get one matched event GET
One matched event by event_id. Missing or hidden from the plan is 404; the response never says which.