curl --request GET \
--url https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads \
--header 'Authorization: Bearer <token>'import requests
url = "https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads', 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://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"items": [
{
"chatId": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"user": {
"id": 123,
"type": "internal",
"email": "<string>",
"externalId": "<string>",
"name": "<string>"
},
"agentId": 123,
"initialContext": "<string>",
"source": "web",
"title": "<string>",
"turns": [
{
"files": [
"<string>"
],
"index": 123,
"messageId": "<string>",
"prompt": "<string>",
"queries": [
{
"messageId": "<string>",
"status": "success",
"tool": "<string>",
"dataSource": "<string>",
"error": "<string>",
"feedback": {
"createdAt": "<string>",
"isPositive": true,
"userId": 123
},
"rowCount": 123,
"sql": "<string>",
"title": "<string>"
}
],
"tools": [
"<string>"
],
"endedAt": "<string>",
"finalAnswer": "<string>",
"startedAt": "<string>"
}
]
}
],
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": true,
"endCursor": "<string>",
"startCursor": "<string>"
}
}List chat threads
curl --request GET \
--url https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads \
--header 'Authorization: Bearer <token>'import requests
url = "https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads', 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://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://{tenant}.cubecloud.dev/api/v1/deployments/{deploymentId}/chat-history/threads")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"items": [
{
"chatId": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"user": {
"id": 123,
"type": "internal",
"email": "<string>",
"externalId": "<string>",
"name": "<string>"
},
"agentId": 123,
"initialContext": "<string>",
"source": "web",
"title": "<string>",
"turns": [
{
"files": [
"<string>"
],
"index": 123,
"messageId": "<string>",
"prompt": "<string>",
"queries": [
{
"messageId": "<string>",
"status": "success",
"tool": "<string>",
"dataSource": "<string>",
"error": "<string>",
"feedback": {
"createdAt": "<string>",
"isPositive": true,
"userId": 123
},
"rowCount": 123,
"sql": "<string>",
"title": "<string>"
}
],
"tools": [
"<string>"
],
"endedAt": "<string>",
"finalAnswer": "<string>",
"startedAt": "<string>"
}
]
}
],
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": true,
"endCursor": "<string>",
"startCursor": "<string>"
}
}includeTurns=true to get each thread’s turns in the same response. A turn is one prompt and everything the agent did to answer it: the final answer, the tools it called, and each query it ran with its SQL, status, row count and any thumbs-up/down feedback. Query result rows are never included. A prompt, answer or SQL longer than 20,000 characters, or an error longer than 2,000, is cut and ends in …. A page holds up to 200 threads, or 50 with turns; a larger first is lowered to that.
For an incremental export, keep the newest updatedAt you have seen and pass it as updatedAfter next time.
Chat history export is in preview: when it is not enabled for the account, 404 is returned.Authorizations
Token authentication. Send Authorization: Bearer <YOUR_TOKEN>.
Path Parameters
Query Parameters
Only threads whose createdAt is at or after this ISO 8601 date or date-time.
^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$Only threads whose createdAt is at or before this ISO 8601 date-time. A date alone (2026-10-01) includes that whole day, UTC.
^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$Only threads whose updatedAt is at or after this ISO 8601 date or date-time. A thread is updated by every new turn, so this is the filter for incremental exports.
^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$Only threads whose updatedAt is at or before this ISO 8601 date-time. A date alone (2026-10-01) includes that whole day, UTC.
^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$Cube user ids. Repeat the parameter to match any of several values, up to 100.
100User emails, matched case-insensitively against Cube users and against the email an embedded user signed in with. Repeat the parameter to match any of several values, up to 100.
100External ids of embedded-analytics users, as your application passed them. Repeat the parameter to match any of several values, up to 100.
100internal for Cube users, external for embedded-analytics users. Combines with the user filters above, which match any of their values.
internal, external Where the thread was started: web (the Cube app or embedded analytics), api (the Chat API), mcp, slack or scheduled (a scheduled task). Repeat the parameter to match any of several values, up to 100.
100web, api, mcp, slack, scheduled The surface inside the app the thread began on. Repeat the parameter to match any of several values, up to 100.
100chat, workbook, model, dashboard, external, mcp, ai-widget, onboarding, explore, connection_setup, slack_dm, published-dashboard, sheets Agent ids; -1 selects the Auto agent. Repeat the parameter to match any of several values, up to 100.
100Case-insensitive match on the thread title or its chat id.
Defaults to updatedAt.
createdAt, updatedAt Defaults to desc.
asc, desc Return every thread with its turns. Pages then default to 20 threads and hold at most 50.
x >= 1