GET /v1/trades for the tape, GET /v1/trades/metrics when you only need
totals.
Trade history
heavy bucket, cost 1 per started 250 rows of limit (so 2 at limit=500).
Request
Out-of-range values are rejected, not clamped. A
window_seconds of
100 or a limit of 1000 returns 400, not the nearest legal value.Example
Response
Records are ordered newest first, deduplicated by trade id, and filtered to
0 < price ≤ 100 with a non-zero size.
Errors
There is no
404. An unknown contract_id returns an empty result, not an
error.
Paging backwards
Repeat the request withbefore set to the oldest timestamp you received
(as integer seconds), while has_more is true.
has_moreonly means “the page came back full.” It is true whenever exactlylimitrecords were returned — it is not a lookahead. Expect one final empty or short page at the end of the tape.
window_secondsalways measures back from now, never frombefore. Page far enough back and your window no longer contains the trades you asked for, so the primary query empties out — at which point the fallback below takes over and paging keeps working.
The empty-window fallback
If the window contains no trades, the query is retried with no lower bound at all (still bounded above bybefore, or now). The response then carries the
most recent trades the contract has before that point, which may be far older
than the window you asked for.
Inspect
oldest_available_ts to detect this. A value far outside your
requested window means you are looking at the fallback, not at trades inside
window_seconds.Notes
- The implicit “now” upper bound is quantized to a few seconds so repeated
polls share a server-side cache. Responses are
Cache-Control: private, max-age=5with no ETag, so this route never returns304. - Prices always refer to the outcome actually traded. To express a trade on
any outcome in terms of the other outcome of a binary market, use
100 − price.
Volume metrics
light bucket, flat 1 unit.
Request
Example
Response
Notional is computed per trade as
size × price / 100.
Errors
A contract with no trades in the window returns
200 with zeroed volumes and
outcome_0_volume_share_pct: 50.0, not a 404.
Notes
outcome_0 / outcome_1 are not a guaranteed Yes/No mapping. On Kalshi
they are the yes and no sides. On every other venue they are the two
highest-volume outcome tokens in the window, in descending volume order —
a volume ranking, recomputed per window. If you need a specific outcome,
resolve its token_id from
market metadata./v1/trades, this endpoint is Cache-Control: private, max-age=5 with
no ETag.
