API reference
These pages are generated from the public OpenAPI spec, which is also served as it is at /openapi.yaml. Generate a client from it, or read it alongside these pages.
- Base URL:
https://api.skewtape.com - Authentication: send your API key in the
X-API-Keyheader. Create keys in the dashboard. - Pagination: every list answers
{"data": [...], "next_cursor": ...}. Passnext_cursorback ascursorfor the next page; it is null on the last page.limitsets the page size. - Errors: every error has the same shape and links to its section of Errors.
The reference shows no live data and sends no request: there is no "try it" panel. Call the API from your own code with your key.
Powered by Kalshi Research
Errors
Every error code the Skewtape API returns, what happened and what to do. Each code has its own section, linked from the docs_url of every error.
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.