Fetch candles for up to 200 contracts in one request
Batched form of GET /candles. Accepts up to 200 per-contract requests and returns results in the same order, index-tagged.
Auth: same as GET /candles — require_auth_or_admin_or_apikey, no scope required.
Cache / data source: each item is checked against the cache in parallel first; only uncached items are fetched fresh. Items with rebuild: true always skip the cache regardless of a hit.
Fail-fast, partial-failure semantics: an empty series for an item is returned as "candles": [] (not an error) — the client renders an empty chart and expects later bars via the live WebSocket feed; there is no server-side ingestion retry. If fetching fails for some items but others were already served from cache, those cached items are still returned; every failed item instead gets "candles": [], "error": "<message>" so the client can distinguish a genuine failure from a legitimately empty window. Only if no item could be served at all does the whole request fail with 500.
Validation (all 400): body must contain a JSON array under requests (or the legacy alias items); the array must be non-empty and at most 200 items; each item must be an object with provider, contract_id, timeframe_seconds, start, and end present; the same per-field checks as GET /candles apply per item (unknown provider, invalid contract_id, disallowed timeframe, unparseable/out-of-order timestamps, negative or non-integer outcome).
curl --request POST \
--url https://data.kairos.trade/candles/batch \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--header 'X-Api-Secret: <api-key>' \
--header 'X-Client-Id: <api-key>' \
--data '
{
"requests": [
{
"provider": "kalshi",
"contract_id": "KXPRESPOLAND-24-DT",
"timeframe_seconds": 60,
"start": "2026-07-21T00:00:00Z",
"end": "2026-07-22T00:00:00Z",
"outcome": 0,
"rebuild": false
},
{
"provider": "polymarket",
"contract_id": "0xabc123...token",
"timeframe_seconds": 3600,
"start": "2026-07-15T00:00:00Z",
"end": "2026-07-22T00:00:00Z"
}
]
}
'import requests
url = "https://data.kairos.trade/candles/batch"
payload = { "requests": [
{
"provider": "kalshi",
"contract_id": "KXPRESPOLAND-24-DT",
"timeframe_seconds": 60,
"start": "2026-07-21T00:00:00Z",
"end": "2026-07-22T00:00:00Z",
"outcome": 0,
"rebuild": False
},
{
"provider": "polymarket",
"contract_id": "0xabc123...token",
"timeframe_seconds": 3600,
"start": "2026-07-15T00:00:00Z",
"end": "2026-07-22T00:00:00Z"
}
] }
headers = {
"X-Client-Id": "<api-key>",
"X-Api-Key": "<api-key>",
"X-Api-Secret": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Client-Id': '<api-key>',
'X-Api-Key': '<api-key>',
'X-Api-Secret': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
requests: [
{
provider: 'kalshi',
contract_id: 'KXPRESPOLAND-24-DT',
timeframe_seconds: 60,
start: '2026-07-21T00:00:00Z',
end: '2026-07-22T00:00:00Z',
outcome: 0,
rebuild: false
},
{
provider: 'polymarket',
contract_id: '0xabc123...token',
timeframe_seconds: 3600,
start: '2026-07-15T00:00:00Z',
end: '2026-07-22T00:00:00Z'
}
]
})
};
fetch('https://data.kairos.trade/candles/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://data.kairos.trade/candles/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'requests' => [
[
'provider' => 'kalshi',
'contract_id' => 'KXPRESPOLAND-24-DT',
'timeframe_seconds' => 60,
'start' => '2026-07-21T00:00:00Z',
'end' => '2026-07-22T00:00:00Z',
'outcome' => 0,
'rebuild' => false
],
[
'provider' => 'polymarket',
'contract_id' => '0xabc123...token',
'timeframe_seconds' => 3600,
'start' => '2026-07-15T00:00:00Z',
'end' => '2026-07-22T00:00:00Z'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>",
"X-Api-Secret: <api-key>",
"X-Client-Id: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://data.kairos.trade/candles/batch"
payload := strings.NewReader("{\n \"requests\": [\n {\n \"provider\": \"kalshi\",\n \"contract_id\": \"KXPRESPOLAND-24-DT\",\n \"timeframe_seconds\": 60,\n \"start\": \"2026-07-21T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\",\n \"outcome\": 0,\n \"rebuild\": false\n },\n {\n \"provider\": \"polymarket\",\n \"contract_id\": \"0xabc123...token\",\n \"timeframe_seconds\": 3600,\n \"start\": \"2026-07-15T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Client-Id", "<api-key>")
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("X-Api-Secret", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://data.kairos.trade/candles/batch")
.header("X-Client-Id", "<api-key>")
.header("X-Api-Key", "<api-key>")
.header("X-Api-Secret", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"requests\": [\n {\n \"provider\": \"kalshi\",\n \"contract_id\": \"KXPRESPOLAND-24-DT\",\n \"timeframe_seconds\": 60,\n \"start\": \"2026-07-21T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\",\n \"outcome\": 0,\n \"rebuild\": false\n },\n {\n \"provider\": \"polymarket\",\n \"contract_id\": \"0xabc123...token\",\n \"timeframe_seconds\": 3600,\n \"start\": \"2026-07-15T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.kairos.trade/candles/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Client-Id"] = '<api-key>'
request["X-Api-Key"] = '<api-key>'
request["X-Api-Secret"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"requests\": [\n {\n \"provider\": \"kalshi\",\n \"contract_id\": \"KXPRESPOLAND-24-DT\",\n \"timeframe_seconds\": 60,\n \"start\": \"2026-07-21T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\",\n \"outcome\": 0,\n \"rebuild\": false\n },\n {\n \"provider\": \"polymarket\",\n \"contract_id\": \"0xabc123...token\",\n \"timeframe_seconds\": 3600,\n \"start\": \"2026-07-15T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"index": 0,
"candles": [
{
"contract_id": "KXPRESPOLAND-24-DT",
"timeframe_seconds": 60,
"bucket_start": "2026-07-21T14:32:00+00:00",
"open": 63.5,
"high": 64,
"low": 63,
"close": 63.8,
"volume": 1250,
"token_id": "71321045679252212594626385532706912750332728571942532289631379312455583992563"
}
],
"error": "Candle batch fetch failed"
}
]
}{
"detail": "Max 200 requests"
}{
"detail": "Not authenticated"
}{
"detail": "Invite required"
}{
"detail": "Request body too large"
}{
"detail": [
{}
]
}{
"error": "Rate limit exceeded: 100 per 1 minute"
}{
"detail": "Invalid provider"
}Authorizations
Credential client id (kairos_ck_...). Must be sent together with X-Api-Key and X-Api-Secret.
64-char hex API key.
64-char hex API secret.
Body
requests is the primary field name; the router also accepts a legacy items key with the identical array shape as a fallback if requests is absent.
1 - 200 elementsShow child attributes
Show child attributes
Response
Index-ordered results, one per request item. A failed item carries an error string and an empty candles array instead of a 5xx for the whole batch.
Index-ordered, one entry per request item.
Show child attributes
Show child attributes
Was this page helpful?
curl --request POST \
--url https://data.kairos.trade/candles/batch \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--header 'X-Api-Secret: <api-key>' \
--header 'X-Client-Id: <api-key>' \
--data '
{
"requests": [
{
"provider": "kalshi",
"contract_id": "KXPRESPOLAND-24-DT",
"timeframe_seconds": 60,
"start": "2026-07-21T00:00:00Z",
"end": "2026-07-22T00:00:00Z",
"outcome": 0,
"rebuild": false
},
{
"provider": "polymarket",
"contract_id": "0xabc123...token",
"timeframe_seconds": 3600,
"start": "2026-07-15T00:00:00Z",
"end": "2026-07-22T00:00:00Z"
}
]
}
'import requests
url = "https://data.kairos.trade/candles/batch"
payload = { "requests": [
{
"provider": "kalshi",
"contract_id": "KXPRESPOLAND-24-DT",
"timeframe_seconds": 60,
"start": "2026-07-21T00:00:00Z",
"end": "2026-07-22T00:00:00Z",
"outcome": 0,
"rebuild": False
},
{
"provider": "polymarket",
"contract_id": "0xabc123...token",
"timeframe_seconds": 3600,
"start": "2026-07-15T00:00:00Z",
"end": "2026-07-22T00:00:00Z"
}
] }
headers = {
"X-Client-Id": "<api-key>",
"X-Api-Key": "<api-key>",
"X-Api-Secret": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Client-Id': '<api-key>',
'X-Api-Key': '<api-key>',
'X-Api-Secret': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
requests: [
{
provider: 'kalshi',
contract_id: 'KXPRESPOLAND-24-DT',
timeframe_seconds: 60,
start: '2026-07-21T00:00:00Z',
end: '2026-07-22T00:00:00Z',
outcome: 0,
rebuild: false
},
{
provider: 'polymarket',
contract_id: '0xabc123...token',
timeframe_seconds: 3600,
start: '2026-07-15T00:00:00Z',
end: '2026-07-22T00:00:00Z'
}
]
})
};
fetch('https://data.kairos.trade/candles/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://data.kairos.trade/candles/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'requests' => [
[
'provider' => 'kalshi',
'contract_id' => 'KXPRESPOLAND-24-DT',
'timeframe_seconds' => 60,
'start' => '2026-07-21T00:00:00Z',
'end' => '2026-07-22T00:00:00Z',
'outcome' => 0,
'rebuild' => false
],
[
'provider' => 'polymarket',
'contract_id' => '0xabc123...token',
'timeframe_seconds' => 3600,
'start' => '2026-07-15T00:00:00Z',
'end' => '2026-07-22T00:00:00Z'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>",
"X-Api-Secret: <api-key>",
"X-Client-Id: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://data.kairos.trade/candles/batch"
payload := strings.NewReader("{\n \"requests\": [\n {\n \"provider\": \"kalshi\",\n \"contract_id\": \"KXPRESPOLAND-24-DT\",\n \"timeframe_seconds\": 60,\n \"start\": \"2026-07-21T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\",\n \"outcome\": 0,\n \"rebuild\": false\n },\n {\n \"provider\": \"polymarket\",\n \"contract_id\": \"0xabc123...token\",\n \"timeframe_seconds\": 3600,\n \"start\": \"2026-07-15T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Client-Id", "<api-key>")
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("X-Api-Secret", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://data.kairos.trade/candles/batch")
.header("X-Client-Id", "<api-key>")
.header("X-Api-Key", "<api-key>")
.header("X-Api-Secret", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"requests\": [\n {\n \"provider\": \"kalshi\",\n \"contract_id\": \"KXPRESPOLAND-24-DT\",\n \"timeframe_seconds\": 60,\n \"start\": \"2026-07-21T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\",\n \"outcome\": 0,\n \"rebuild\": false\n },\n {\n \"provider\": \"polymarket\",\n \"contract_id\": \"0xabc123...token\",\n \"timeframe_seconds\": 3600,\n \"start\": \"2026-07-15T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.kairos.trade/candles/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Client-Id"] = '<api-key>'
request["X-Api-Key"] = '<api-key>'
request["X-Api-Secret"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"requests\": [\n {\n \"provider\": \"kalshi\",\n \"contract_id\": \"KXPRESPOLAND-24-DT\",\n \"timeframe_seconds\": 60,\n \"start\": \"2026-07-21T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\",\n \"outcome\": 0,\n \"rebuild\": false\n },\n {\n \"provider\": \"polymarket\",\n \"contract_id\": \"0xabc123...token\",\n \"timeframe_seconds\": 3600,\n \"start\": \"2026-07-15T00:00:00Z\",\n \"end\": \"2026-07-22T00:00:00Z\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"index": 0,
"candles": [
{
"contract_id": "KXPRESPOLAND-24-DT",
"timeframe_seconds": 60,
"bucket_start": "2026-07-21T14:32:00+00:00",
"open": 63.5,
"high": 64,
"low": 63,
"close": 63.8,
"volume": 1250,
"token_id": "71321045679252212594626385532706912750332728571942532289631379312455583992563"
}
],
"error": "Candle batch fetch failed"
}
]
}{
"detail": "Max 200 requests"
}{
"detail": "Not authenticated"
}{
"detail": "Invite required"
}{
"detail": "Request body too large"
}{
"detail": [
{}
]
}{
"error": "Rate limit exceeded: 100 per 1 minute"
}{
"detail": "Invalid provider"
}
