---
title: "Fetch OHLCV candles for a single contract"
method: GET
path: "/candles"
tags: ["Candles"]
---

# Fetch OHLCV candles for a single contract

`GET /candles`

## Request

- Base URL: `https://data.kairos.trade`
- URL: `https://data.kairos.trade/candles`
- Auth: API key in header `X-Client-Id` and API key in header `X-Api-Key` and API key in header `X-Api-Secret`

Returns OHLCV candle bars for one `(provider, contract_id, outcome)` series over `[start, end)`, bucketed at `timeframe_seconds`.

**Auth**: accepts an admin secret (`X-Admin-Secret`), an API key (`X-Client-Id` + `X-Api-Key` + `X-Api-Secret`), or a first-party JWT (`Authorization: Bearer` or `turnkey_session_jwt` cookie). No API-key scope is required for this endpoint — any valid credential can read candles.

**Cache / data source**: responses may be served from cache unless `rebuild=true`, which always bypasses the cache and reconstructs candles from the underlying trade/candle data, then repopulates the cache. `rebuild=true` is for callers that explicitly want fresh data regardless of what's cached.

**Validation** (all return 400): unknown `provider` (must exist in the live provider registry — currently includes `kalshi`, `polymarket`, `dome`, `opinion`); empty or >128-char `contract_id`; `timeframe_seconds` not one of the fixed allowed values; unparseable `start`/`end` (ISO 8601); or `end <= start`. An `outcome` index invalid for the given provider/contract (e.g. an out-of-range index on a binary market) also returns 400.

## Query parameters

- `provider` string, required
- `contract_id` string, required
- `timeframe_seconds` 1 | 60 | 300 | 900 | 3600 | 14400 | 86400, required
- `start` string, date-time, required
- `end` string, date-time, required
- `outcome` integer, nullable
- `rebuild` boolean

## Response `200`

OHLCV series for the requested window.

- CandlesSeriesResponse
  - `candles` CandlesCandle[], required
    - `contract_id` string, required: Contract/market identifier this bar belongs to.
    - `timeframe_seconds` integer, required: Bucket width in seconds.
    - `bucket_start` string, date-time, required: Bucket start time, ISO 8601 UTC.
    - `open` number, required: Opening price, 0-100 cents scale.
    - `high` number, required: High price in the bucket, 0-100 cents scale.
    - `low` number, required: Low price in the bucket, 0-100 cents scale.
    - `close` number, required: Closing price, 0-100 cents scale.
    - `volume` integer, required: Traded size (contracts/shares) within the bucket.
    - `token_id` string: Outcome token identifier, present only when this series is token-scoped (e.g. multi-outcome Polymarket markets).

## Other responses

- `400`: Invalid request — unknown provider, invalid/missing contract_id, disallowed timeframe_seconds, unparseable or out-of-order start/end, or an outcome index invalid for this contract.
- `401`: No valid credential presented — missing/invalid API-key headers, or an invalid/expired session token.
- `403`: Authenticated but not permitted. Three distinct causes: the session user is not invited (`Invite required`), the API key lacks the operation's scope, or API-key access to the requested venue is switched off (`API access is disabled for <provider>`). Admin and API-key callers bypass the invite check; session and admin callers bypass scope and venue checks.
- `422`: Request failed FastAPI parameter validation.
- `429`: Rate limit exceeded for this route's sliding window, keyed on the session `sub` when authenticated and on the trusted client IP otherwise. Honor `Retry-After`. A per-API-key data ceiling (set per credential) rejects with `{"detail": "API key data rate limit exceeded"}` instead of the `error` envelope below.
- `500`: Candle fetch failed (cache or ClickHouse read error).

---

[API](https://skmtc.dev/kairos/apis/kairos-data-api.md) - [All operations](https://skmtc.dev/kairos/apis/kairos-data-api/llms.txt) - [OpenAPI document](https://skmtc.dev/kairos/apis/kairos-data-api/revisions/cf6b76079e38?raw)
