{"openapi":"3.1.0","info":{"title":"Sardine API: Kalshi crypto settlement history","version":"0.2.0","summary":"How often Kalshi crypto up/down contracts settled YES, counted, with a public record","description":"Sardine counts, for Kalshi's BTC, ETH and XRP up/down contracts (15-minute and hourly), how often contracts this far from the strike with this much time left settled YES, from every settled window in a trailing window of history. The numbers are counts of what happened, not forecasts or advice; Kalshi's own price is usually the better predictor, and every number the site has shown is written down the moment it is shown and scored publicly against the settled result at https://sardine.info/record.\n\nLicence: aggregates (tables, rates, the record, CSV files) are CC BY 4.0, credit \"Sardine (sardine.info)\"; market prices are Kalshi's. Per-contract price history is not served through this API, and Kalshi's live prices are not redistributed either, pending Kalshi's Redistribution licence (read them from Kalshi's own API and pass kalshi_ask to /v1/settlement-rate for the fee and the gap); the backtest replays Sardine's own per-second recordings on the server and returns results only, never rows.\n\nLimits (free with signup): 25 calls per UTC day without a key, to try it; 10,000 with a free key (an email, no card) from https://sardine.info/signup, sent as `Authorization: Bearer <key>` or `?key=`. Add `format=csv` to any endpoint for a file that opens in Excel.\n\nUnits everywhere: prices and rates are probabilities 0..1 (0.42 = 42 cents, 42%); fields named `_cents` are in cents; times are UTC epoch seconds; `minutes_left` is time to the contract's close.\n\nSame data over MCP: `uvx sardine-mcp` (stdio) or https://sardine.info/mcp (streamable HTTP). Human page: https://sardine.info/developers. Method: https://sardine.info/how.","contact":{"name":"Sardine","url":"https://sardine.info/developers"},"license":{"name":"CC BY 4.0 (aggregates)","url":"https://creativecommons.org/licenses/by/4.0/"}},"externalDocs":{"description":"Developer page, method and public record","url":"https://sardine.info/developers"},"servers":[{"url":"https://sardine.info","description":"Production"}],"tags":[{"name":"history","description":"Counts of what settled, by situation"},{"name":"live","description":"What is open on Kalshi right now, with the count beside it"},{"name":"record","description":"What Sardine published versus what settled"},{"name":"backtest","description":"Replay a rule on recorded quotes, after fees; results only"},{"name":"data","description":"Downloadable files"},{"name":"experimental","description":"Published for builders to try; shape may change"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Optional free key from https://sardine.info/signup; raises the daily limit."}},"schemas":{"About":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."},"Markets":{"type":"object","properties":{"markets":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Series key, e.g. BTC-15M"},"asset":{"type":["string","null"]},"window":{"type":["string","null"]},"window_seconds":{"type":["integer","null"]},"kalshi_series":{"type":["string","null"]},"served_now":{"type":"boolean"},"calibration_worst_miss":{"type":["number","null"],"description":"Largest bucket miss, probability units (0.055 = 5.5 points)"},"calibration_basis":{"type":["string","null"]},"under_review":{"type":["string","null"],"description":"Why the words are withheld, or null"}},"additionalProperties":true}},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true,"required":["markets"]},"BoardRow":{"type":"object","properties":{"market":{"type":"string"},"contract":{"type":["string","null"]},"ticker":{"type":"string"},"side":{"type":["string","null"],"description":"YES or NO"},"minutes_left":{"type":["number","null"]},"historical_settlement_rate":{"type":["number","null"],"description":"0..1; null when no cell matches"},"interval_low":{"type":["number","null"]},"interval_high":{"type":["number","null"]},"windows_counted":{"type":["integer","null"]},"summary":{"type":"string","description":"One sentence, no price in it"},"kalshi_url":{"type":["string","null"],"description":"Kalshi's own page for the contract"}},"additionalProperties":true},"Board":{"type":"object","properties":{"served_at":{"type":["number","null"]},"contracts_scanned":{"type":["integer","null"]},"kalshi_prices":{"type":"string","description":"Why there is no price field, and where to get one"},"rows":{"type":"array","items":{"$ref":"#/components/schemas/BoardRow"}},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true,"required":["rows"]},"SettlementRate":{"type":"object","properties":{"asset":{"type":["string","null"]},"side":{"type":["string","null"]},"spot_now":{"type":["number","null"]},"strike":{"type":["number","null"]},"minutes_left":{"type":["number","null"]},"historical_settlement_rate":{"type":["number","null"],"description":"0..1; null when fewer than 40 windows match"},"interval_95":{"type":"array","items":{"type":["number","null"]},"minItems":2,"maxItems":2},"windows_counted":{"type":["integer","null"]},"distance_in_vol_units":{"type":["number","null"],"description":"z"},"sigma_1m":{"type":["number","null"],"description":"Standard deviation of 1-minute log returns over the last 60 minutes"},"z_bucket":{"type":["array","null"],"items":{"type":["number","null"]},"description":"[z_lo, z_hi] of the cell used"},"reason":{"type":["string","null"],"description":"Present when there is no rate: why"},"kalshi_ask":{"type":["number","null"],"description":"Echo of the ask you passed"},"kalshi_fee_per_contract":{"type":["number","null"]},"kalshi_all_in_price":{"type":["number","null"],"description":"ask + fee"},"gap_after_fee":{"type":["number","null"],"description":"rate minus all-in price, signed, 0..1 units"},"gap_cents":{"type":["number","null"],"description":"The same in cents"},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true},"TableCell":{"type":"object","properties":{"z_low":{"type":["number","null"]},"z_high":{"type":["number","null"]},"seconds_left":{"type":["integer","null"]},"settled_yes_share":{"type":["number","null"]},"interval_low":{"type":["number","null"]},"interval_high":{"type":["number","null"]},"windows_counted":{"type":["integer","null"]}},"additionalProperties":true},"Table":{"type":"object","properties":{"key":{"type":["string","null"]},"kalshi_series":{"type":["string","null"]},"built_from_windows":{"type":["integer","null"]},"rows":{"type":"array","items":{"$ref":"#/components/schemas/TableCell"}},"how_to_read":{"type":"string"},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true,"required":["rows"]},"Record":{"type":"object","properties":{"record_since_unix":{"type":["integer","null"]},"summary":{"type":"object","additionalProperties":{"type":"object","properties":{"worst_miss_points":{"type":["number","null"]},"worst_bucket":{"type":["string","null"]}},"additionalProperties":true}},"rows":{"type":"array","items":{"type":"object","properties":{"market":{"type":"string"},"bucket":{"type":["string","null"]},"windows":{"type":["integer","null"]},"we_said":{"type":["number","null"]},"it_settled":{"type":["number","null"]},"miss_points":{"type":["number","null"]},"counted":{"type":["boolean","null"]}},"additionalProperties":true}},"full_record":{"type":"string","description":"URL"},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true},"Datasets":{"type":"object","properties":{"generated_utc":{"type":["string","null"]},"rows":{"type":"array","items":{"type":"object","properties":{"label":{"type":["string","null"]},"url":{"type":"string"},"rows":{"type":["integer","null"]},"independent_windows":{"type":["integer","null"]},"from":{"type":["string","null"]},"to":{"type":["string","null"]},"size_bytes":{"type":["integer","null"]}},"additionalProperties":true}},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true},"BacktestSummary":{"type":"object","properties":{"trades":{"type":"integer","description":"Windows traded (one per window)"},"contracts":{"type":"integer","description":"Contracts filled in total"},"win_rate":{"type":["number","null"],"description":"Share of trades that settled in the bought side's favour"},"avg_price_cents":{"type":["number","null"]},"avg_fee_cents":{"type":["number","null"]},"pnl_dollars":{"type":"number","description":"Net profit after fees, all contracts"},"pnl_cents_per_contract":{"type":["number","null"],"description":"Mean net cents per contract; the headline"},"return_per_dollar_risked":{"type":["number","null"]},"t_stat":{"type":["number","null"]},"ci95_cents_per_contract":{"type":["array","null"],"items":{"type":"number"},"description":"Bootstrap 95% interval of the mean, cents per contract"}},"additionalProperties":true,"description":"Aggregates of one replay. Never rows."},"Bucket":{"type":"object","properties":{"range":{"type":"string"},"trades":{"type":"integer"},"win_rate":{"type":["number","null"]},"pnl_cents_per_contract":{"type":["number","null"]}},"additionalProperties":true},"Backtest":{"type":"object","properties":{"rule":{"type":"object","additionalProperties":true,"description":"The rule as run"},"same_rule_zero_latency":{"type":"object","properties":{"trades":{"type":"integer","description":"Windows traded (one per window)"},"contracts":{"type":"integer","description":"Contracts filled in total"},"win_rate":{"type":["number","null"],"description":"Share of trades that settled in the bought side's favour"},"avg_price_cents":{"type":["number","null"]},"avg_fee_cents":{"type":["number","null"]},"pnl_dollars":{"type":"number","description":"Net profit after fees, all contracts"},"pnl_cents_per_contract":{"type":["number","null"],"description":"Mean net cents per contract; the headline"},"return_per_dollar_risked":{"type":["number","null"]},"t_stat":{"type":["number","null"]},"ci95_cents_per_contract":{"type":["array","null"],"items":{"type":"number"},"description":"Bootstrap 95% interval of the mean, cents per contract"}},"additionalProperties":true,"description":"Aggregates of one replay. Never rows."},"coverage":{"type":"object","properties":{"market":{"type":"string"},"from":{"type":"string","description":"YYYY-MM-DD"},"to":{"type":"string","description":"YYYY-MM-DD"},"windows_replayed":{"type":"integer"},"windows_missing_result":{"type":"integer"},"triggers":{"type":["integer","null"],"description":"Rule backtest only: seconds the rule fired"},"history_lookups_by_spot_source":{"type":["object","null"],"additionalProperties":{"type":"integer"}}},"additionalProperties":true},"result":{"type":"object","properties":{"trades":{"type":"integer","description":"Windows traded (one per window)"},"contracts":{"type":"integer","description":"Contracts filled in total"},"win_rate":{"type":["number","null"],"description":"Share of trades that settled in the bought side's favour"},"avg_price_cents":{"type":["number","null"]},"avg_fee_cents":{"type":["number","null"]},"pnl_dollars":{"type":"number","description":"Net profit after fees, all contracts"},"pnl_cents_per_contract":{"type":["number","null"],"description":"Mean net cents per contract; the headline"},"return_per_dollar_risked":{"type":["number","null"]},"t_stat":{"type":["number","null"]},"ci95_cents_per_contract":{"type":["array","null"],"items":{"type":"number"},"description":"Bootstrap 95% interval of the mean, cents per contract"}},"additionalProperties":true,"description":"Aggregates of one replay. Never rows."},"stability":{"type":"object","properties":{"first_half_cents_per_contract":{"type":["number","null"]},"second_half_cents_per_contract":{"type":["number","null"]},"same_sign":{"type":"boolean"},"note":{"type":"string"}},"additionalProperties":true},"by_minutes_left":{"type":"array","items":{"type":"object","properties":{"range":{"type":"string"},"trades":{"type":"integer"},"win_rate":{"type":["number","null"]},"pnl_cents_per_contract":{"type":["number","null"]}},"additionalProperties":true}},"by_price_cents":{"type":"array","items":{"type":"object","properties":{"range":{"type":"string"},"trades":{"type":"integer"},"win_rate":{"type":["number","null"]},"pnl_cents_per_contract":{"type":["number","null"]}},"additionalProperties":true}},"warnings":{"type":"array","items":{"type":"string"}},"assumptions":{"type":"array","items":{"type":"string"}},"reminder":{"type":"string"},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true,"required":["result"]},"Signal":{"type":"object","properties":{"ts":{"type":"integer","description":"UTC epoch seconds"},"side":{"type":"string","enum":["YES","NO"]},"contracts":{"type":"integer","description":"1..100000, default 10"}},"additionalProperties":true,"required":["ts","side"]},"SignalsRequest":{"type":"object","properties":{"market":{"type":"string","enum":["BTC-15M","ETH-15M","XRP-15M"]},"signals":{"type":"array","items":{"$ref":"#/components/schemas/Signal"},"description":"At most 5,000"},"latency_seconds":{"type":"integer","description":"0..30, default 2"},"start_date":{"type":["string","null"],"description":"YYYY-MM-DD"},"end_date":{"type":["string","null"],"description":"YYYY-MM-DD"}},"additionalProperties":true,"required":["signals"]},"BacktestSignals":{"type":"object","properties":{"signals":{"type":"object","properties":{"given":{"type":"integer"},"used":{"type":"integer"},"outside_data":{"type":"integer"},"ignored_same_window":{"type":"integer"},"latency_seconds":{"type":"integer"}},"additionalProperties":true},"signals_used":{"type":"integer"},"signals_outside_data":{"type":"integer"},"same_signals_zero_latency":{"type":"object","properties":{"trades":{"type":"integer","description":"Windows traded (one per window)"},"contracts":{"type":"integer","description":"Contracts filled in total"},"win_rate":{"type":["number","null"],"description":"Share of trades that settled in the bought side's favour"},"avg_price_cents":{"type":["number","null"]},"avg_fee_cents":{"type":["number","null"]},"pnl_dollars":{"type":"number","description":"Net profit after fees, all contracts"},"pnl_cents_per_contract":{"type":["number","null"],"description":"Mean net cents per contract; the headline"},"return_per_dollar_risked":{"type":["number","null"]},"t_stat":{"type":["number","null"]},"ci95_cents_per_contract":{"type":["array","null"],"items":{"type":"number"},"description":"Bootstrap 95% interval of the mean, cents per contract"}},"additionalProperties":true,"description":"Aggregates of one replay. Never rows."},"coverage":{"type":"object","properties":{"market":{"type":"string"},"from":{"type":"string","description":"YYYY-MM-DD"},"to":{"type":"string","description":"YYYY-MM-DD"},"windows_replayed":{"type":"integer"},"windows_missing_result":{"type":"integer"},"triggers":{"type":["integer","null"],"description":"Rule backtest only: seconds the rule fired"},"history_lookups_by_spot_source":{"type":["object","null"],"additionalProperties":{"type":"integer"}}},"additionalProperties":true},"result":{"type":"object","properties":{"trades":{"type":"integer","description":"Windows traded (one per window)"},"contracts":{"type":"integer","description":"Contracts filled in total"},"win_rate":{"type":["number","null"],"description":"Share of trades that settled in the bought side's favour"},"avg_price_cents":{"type":["number","null"]},"avg_fee_cents":{"type":["number","null"]},"pnl_dollars":{"type":"number","description":"Net profit after fees, all contracts"},"pnl_cents_per_contract":{"type":["number","null"],"description":"Mean net cents per contract; the headline"},"return_per_dollar_risked":{"type":["number","null"]},"t_stat":{"type":["number","null"]},"ci95_cents_per_contract":{"type":["array","null"],"items":{"type":"number"},"description":"Bootstrap 95% interval of the mean, cents per contract"}},"additionalProperties":true,"description":"Aggregates of one replay. Never rows."},"stability":{"type":"object","properties":{"first_half_cents_per_contract":{"type":["number","null"]},"second_half_cents_per_contract":{"type":["number","null"]},"same_sign":{"type":"boolean"},"note":{"type":"string"}},"additionalProperties":true},"by_minutes_left":{"type":"array","items":{"type":"object","properties":{"range":{"type":"string"},"trades":{"type":"integer"},"win_rate":{"type":["number","null"]},"pnl_cents_per_contract":{"type":["number","null"]}},"additionalProperties":true}},"by_price_cents":{"type":"array","items":{"type":"object","properties":{"range":{"type":"string"},"trades":{"type":"integer"},"win_rate":{"type":["number","null"]},"pnl_cents_per_contract":{"type":["number","null"]}},"additionalProperties":true}},"warnings":{"type":"array","items":{"type":"string"}},"assumptions":{"type":"array","items":{"type":"string"}},"reminder":{"type":"string"},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true,"required":["result","signals_used"]},"ZNow":{"type":"object","properties":{"asset":{"type":"string"},"strike":{"type":"number"},"minutes_left":{"type":["number","null"]},"spot_now":{"type":["number","null"]},"sigma_1m":{"type":["number","null"]},"z":{"type":["number","null"],"description":"ln(spot/strike) / (sigma_1m * sqrt(max(1, tau_s - 40) / 60))"},"z_bucket":{"type":["array","null"],"items":{"type":["number","null"]}},"formula":{"type":"string"},"reason":{"type":["string","null"]},"about":{"type":"object","properties":{"source":{"type":"string"},"what_this_is":{"type":"string"},"market_data":{"type":"string"},"method":{"type":"string","description":"URL"},"calls_remaining_today":{"type":["integer","null"],"description":"Calls left today for this caller (also in X-RateLimit-Remaining)"}},"additionalProperties":true,"description":"Attached to every JSON response: what the numbers are and where they come from."}},"additionalProperties":true}}},"security":[{},{"bearer":[]}],"paths":{"/v1/markets":{"get":{"operationId":"listMarkets","tags":["history"],"summary":"Series covered and how accurate each table has been","description":"One row per series (BTC-15M, ETH-15M, XRP-15M, BTC-1H, ETH-1H): whether it is served, how many independent settled windows its table rests on, the worst bucket miss of its split-half self-check against the 6-point limit, and whether its gaps have ever been shown to pay (`edge`, false for every series today). Start here.\n\nExample: `https://sardine.info/v1/markets`","parameters":[{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Markets"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}}},"/v1/board":{"get":{"operationId":"liveBoard","tags":["live"],"summary":"Open contracts now with the historical count per contract (Kalshi's prices not included)","description":"Every live contract on the served 15-minute and hourly boards: ticker, strike, minutes left, and the historical settlement rate for that situation with its interval and sample size. Kalshi's live prices are NOT included, pending Kalshi's Redistribution licence: read them from Kalshi's own API, then pass kalshi_ask to /v1/settlement-rate for the fee and the gap.\n\nExample: `https://sardine.info/v1/board?market=BTC-15M&limit=5`","parameters":[{"name":"market","in":"query","required":false,"description":"Restrict to one series key.","schema":{"type":"string","enum":["BTC-15M","ETH-15M","XRP-15M","BTC-1H","ETH-1H"]},"example":"BTC-15M"},{"name":"limit","in":"query","required":false,"description":"Rows to return, nearest to the money first.","schema":{"type":"integer"},"example":10},{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Board"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}}},"/v1/settlement-rate":{"get":{"operationId":"settlementRate","tags":["history"],"summary":"Historical settlement rate for one situation","description":"Given the asset, the window length, the strike and the minutes left, returns how often contracts in that situation settled YES (`rate`, 0..1), a 95% Wilson interval, the number of independent settled windows, and the distance band used. Spot is read live. Pass `kalshi_ask` (0..1) to get Kalshi's taker fee and the gap after it. Returns no number when fewer than 40 past windows match or under 2 minutes are left.\n\nExample: `https://sardine.info/v1/settlement-rate?asset=BTC&window_minutes=15&strike=79000&minutes_left=5&kalshi_ask=0.42`","parameters":[{"name":"asset","in":"query","required":true,"description":"Coin.","schema":{"type":"string","enum":["BTC","ETH","XRP"]},"example":"BTC"},{"name":"window_minutes","in":"query","required":true,"description":"Contract length in minutes.","schema":{"type":"integer","enum":[15,60]},"example":15},{"name":"strike","in":"query","required":true,"description":"The contract's strike in USD.","schema":{"type":"number"},"example":79000},{"name":"minutes_left","in":"query","required":true,"description":"Minutes to close (2 to 15, or to 60 for hourly).","schema":{"type":"number"},"example":5},{"name":"side","in":"query","required":false,"description":"YES (default) or NO: the rate for that side.","schema":{"type":"string","enum":["YES","NO"]},"example":"YES"},{"name":"kalshi_ask","in":"query","required":false,"description":"Kalshi's ask for the side, 0..1, to compute the fee and gap.","schema":{"type":"number"},"example":0.42},{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettlementRate"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}}},"/v1/table":{"get":{"operationId":"rateTable","tags":["history"],"summary":"The full lookup table for one series","description":"Every cell of the served table: distance from the strike in volatility units (0.5-sigma buckets) by seconds left, with the settled-YES rate, the 95% interval and the window count. Built on the trailing 60 days of settled windows and rebuilt daily.\n\nExample: `https://sardine.info/v1/table?asset=BTC&window_minutes=15&format=csv`","parameters":[{"name":"asset","in":"query","required":false,"description":"Coin.","schema":{"type":"string","enum":["BTC","ETH","XRP"]},"example":"BTC"},{"name":"window_minutes","in":"query","required":false,"description":"15 or 60.","schema":{"type":"integer","enum":[15,60]},"example":15},{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Table"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}}},"/v1/record":{"get":{"operationId":"trackRecord","tags":["record"],"summary":"What Sardine published versus what settled","description":"The public scorecard, read back from the published file, never recomputed: for each price bucket, the share the table said would settle YES, the share that did, and the miss in points over 200 or more windows; plus the split-half self-check per series.\n\nExample: `https://sardine.info/v1/record`","parameters":[{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Record"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}}},"/v1/datasets":{"get":{"operationId":"listDatasets","tags":["data"],"summary":"Downloadable CSV history files","description":"The CC BY 4.0 files behind the site: per-window history per series, the published record, and the tables, each with its row count, size and URL.\n\nExample: `https://sardine.info/v1/datasets`","parameters":[{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Datasets"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}}},"/v1/backtest":{"get":{"operationId":"backtestRule","tags":["backtest"],"summary":"Replay a trading rule on recorded per-second Kalshi quotes, after fees (free key required)","description":"States a rule (which side, when, at what price or gap) and replays it over Sardine's per-second recordings of Kalshi's 15-minute contracts: at most one trade per window, a limit order at the ask seen at the trigger placed after `latency_seconds`, filled only up to the size resting at that ask, Kalshi's 7% x p x (1-p) taker fee rounded up per order, settlement by Kalshi's official result. Returns aggregates only: net cents per contract with a 95% interval, win rate, trade count, a zero-latency comparison, stability across halves, breakdowns and warnings. A rule that only works at zero latency was feeding on quotes that were already gone, and the result says so.\n\nExample: `https://sardine.info/v1/backtest?market=BTC-15M&side=NO&min_gap_cents=5&min_minutes_left=2&max_minutes_left=5`","parameters":[{"name":"market","in":"query","required":false,"description":"Series.","schema":{"type":"string","enum":["BTC-15M","ETH-15M"]},"example":"BTC-15M"},{"name":"side","in":"query","required":false,"description":"YES or NO.","schema":{"type":"string","enum":["YES","NO"]},"example":"NO"},{"name":"min_minutes_left","in":"query","required":false,"description":"Trigger only with at least this many minutes left.","schema":{"type":"number"},"example":2},{"name":"max_minutes_left","in":"query","required":false,"description":"Trigger only with at most this many minutes left.","schema":{"type":"number"},"example":5},{"name":"min_price_cents","in":"query","required":false,"description":"Only when the side's ask is at least this, in cents.","schema":{"type":"number"},"example":20},{"name":"max_price_cents","in":"query","required":false,"description":"Only when the side's ask is at most this, in cents.","schema":{"type":"number"},"example":80},{"name":"min_gap_cents","in":"query","required":false,"description":"Only when history exceeds price-with-fee by at least this, in cents.","schema":{"type":"number"},"example":5},{"name":"max_gap_cents","in":"query","required":false,"description":"Upper bound on that gap, in cents.","schema":{"type":"number"},"example":20},{"name":"contracts","in":"query","required":false,"description":"Contracts per trade (fills are capped by resting size).","schema":{"type":"integer"},"example":10},{"name":"latency_seconds","in":"query","required":false,"description":"Seconds between seeing the quote and the order (default 2).","schema":{"type":"integer"},"example":2},{"name":"start_date","in":"query","required":false,"description":"First day, YYYY-MM-DD (UTC). Without dates the run covers the most recent 14 days; a run may span at most 21 days.","schema":{"type":"string"},"example":"2026-09-10"},{"name":"end_date","in":"query","required":false,"description":"Last day, YYYY-MM-DD (UTC).","schema":{"type":"string"},"example":"2026-10-26"},{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Backtest"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}},"post":{"operationId":"backtestSignals","tags":["backtest"],"summary":"Replay YOUR OWN signals on recorded per-second Kalshi quotes, after fees (free key required)","description":"Send your bot's signals and Sardine replays them with the same engine as the rule backtest: for each signal, the ask seen at that second for that side, a limit order landing after `latency_seconds`, filled only up to the size resting there, Kalshi's 7% x p x (1-p) taker fee rounded up per order, settlement by Kalshi's official result. One trade per 15-minute window: the first signal in a window is used, later ones are counted in `signals.ignored_same_window`. At most 5,000 signals; the signals' span may cover at most 21 days of recorded windows. Aggregates only, never rows. Body is JSON, or `text/csv` with a header row `ts,side,contracts` (then `market` and `latency_seconds` come from the query string).\n\nExample: `curl -X POST -H 'Authorization: Bearer <key>' -H 'Content-Type: application/json' -d '{\"market\":\"BTC-15M\",\"signals\":[{\"ts\":1793020000,\"side\":\"YES\",\"contracts\":10}],\"latency_seconds\":2}' https://sardine.info/v1/backtest`","parameters":[{"name":"market","in":"query","required":false,"description":"Series (JSON body wins when present).","schema":{"type":"string","enum":["BTC-15M","ETH-15M","XRP-15M"]},"example":"BTC-15M"},{"name":"latency_seconds","in":"query","required":false,"description":"Seconds between the signal and the order (default 2).","schema":{"type":"integer"},"example":2}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignalsRequest"}},"text/csv":{"schema":{"type":"string","description":"Header row `ts,side,contracts`, one signal per line; ts in UTC epoch seconds."}}}},"responses":{"200":{"description":"OK. Aggregates only.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BacktestSignals"}}}},"400":{"description":"A signal or parameter is malformed, or the signals span too much data; the body says which."},"401":{"description":"A free key is required: https://sardine.info/signup"},"413":{"description":"Body over 2 MB."},"429":{"description":"Daily limit reached."}}}},"/v1/z":{"get":{"operationId":"zNow","tags":["history"],"summary":"Where a contract sits in the table's coordinates right now","description":"For a builder running the table offline against Kalshi's own feed: live spot, the 1-minute realised vol the lookup uses (sigma_1m), z = ln(spot/strike) / (sigma_1m * sqrt(max(1, tau_s - 40) / 60)), and the 0.5-sigma bucket. No settlement rate here; pair it with /v1/table. Returns `reason` and no z where the table has no cell for the situation (beyond 3 sigma or under 2 minutes).\n\nExample: `https://sardine.info/v1/z?asset=BTC&window_minutes=15&strike=79800&minutes_left=7`","parameters":[{"name":"asset","in":"query","required":true,"description":"Coin.","schema":{"type":"string","enum":["BTC","ETH","XRP"]},"example":"BTC"},{"name":"window_minutes","in":"query","required":true,"description":"15 or 60.","schema":{"type":"integer","enum":[15,60]},"example":15},{"name":"strike","in":"query","required":true,"description":"The contract's strike in USD.","schema":{"type":"number"},"example":79800},{"name":"minutes_left","in":"query","required":true,"description":"Minutes to close.","schema":{"type":"number"},"example":7},{"name":"format","in":"query","required":false,"description":"Response format. `csv` returns a file that opens in Excel; default JSON.","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK. JSON object (or CSV with `format=csv`). Every JSON response carries an `about` block: source, what this is, the method URL and `calls_remaining_today`.","headers":{"X-RateLimit-Limit":{"description":"Calls allowed per UTC day for this caller","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC midnight, epoch seconds, when the count resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZNow"}}}},"400":{"description":"A parameter is missing or out of range; the body says which."},"402":{"description":"Daily limit reached (25 calls a day without a key to try it, 10,000 with a free key from https://sardine.info/signup)."},"404":{"description":"Unknown endpoint; the body lists the valid ones."}}}}}}