Topics available as a conversations filter, optionally scoped to a set of sources.
curl --request POST \
--url https://api.closebot.com/analytics/topics/options \
--header 'Content-Type: application/json' \
--header 'X-CB-KEY: <api-key>' \
--data '
{
"filters": {
"sourceIds": [
"<string>"
],
"dimensions": [
{
"dimension": "<string>",
"operator": "<string>",
"values": [
"<string>"
]
}
]
}
}
'import requests
url = "https://api.closebot.com/analytics/topics/options"
payload = { "filters": {
"sourceIds": ["<string>"],
"dimensions": [
{
"dimension": "<string>",
"operator": "<string>",
"values": ["<string>"]
}
]
} }
headers = {
"X-CB-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-CB-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
filters: {
sourceIds: ['<string>'],
dimensions: [{dimension: '<string>', operator: '<string>', values: ['<string>']}]
}
})
};
fetch('https://api.closebot.com/analytics/topics/options', 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://api.closebot.com/analytics/topics/options",
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([
'filters' => [
'sourceIds' => [
'<string>'
],
'dimensions' => [
[
'dimension' => '<string>',
'operator' => '<string>',
'values' => [
'<string>'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-CB-KEY: <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://api.closebot.com/analytics/topics/options"
payload := strings.NewReader("{\n \"filters\": {\n \"sourceIds\": [\n \"<string>\"\n ],\n \"dimensions\": [\n {\n \"dimension\": \"<string>\",\n \"operator\": \"<string>\",\n \"values\": [\n \"<string>\"\n ]\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-CB-KEY", "<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://api.closebot.com/analytics/topics/options")
.header("X-CB-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"filters\": {\n \"sourceIds\": [\n \"<string>\"\n ],\n \"dimensions\": [\n {\n \"dimension\": \"<string>\",\n \"operator\": \"<string>\",\n \"values\": [\n \"<string>\"\n ]\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.closebot.com/analytics/topics/options")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-CB-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"filters\": {\n \"sourceIds\": [\n \"<string>\"\n ],\n \"dimensions\": [\n {\n \"dimension\": \"<string>\",\n \"operator\": \"<string>\",\n \"values\": [\n \"<string>\"\n ]\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"topics": [
{
"topicId": "<string>",
"name": "<string>",
"slug": "<string>",
"conversationCount": 123
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>"
}Analytics
Topics available as a conversations filter, optionally scoped to a set of sources.
One rule covers both cases: a topic is listed when it has at least one LeadTopic row in scope. That deliberately carries no Status predicate. Only Active slugs ever enter the classifier enum (TopicClassificationPrompt) and the collector refuses to write a fact row for a non-Active topic, so Proposed topics provably have zero rows and fall out on their own — while Merged and Archived topics stay filterable for as long as their history does. Filtering on Status instead would offer topics that always return zero conversations.
Unpaginated by design: the taxonomy is capped at 30 Active topics per agency, so this is a ListPersonas-shaped endpoint, not a GetSources-shaped one.
POST
/
analytics
/
topics
/
options
Topics available as a conversations filter, optionally scoped to a set of sources.
curl --request POST \
--url https://api.closebot.com/analytics/topics/options \
--header 'Content-Type: application/json' \
--header 'X-CB-KEY: <api-key>' \
--data '
{
"filters": {
"sourceIds": [
"<string>"
],
"dimensions": [
{
"dimension": "<string>",
"operator": "<string>",
"values": [
"<string>"
]
}
]
}
}
'import requests
url = "https://api.closebot.com/analytics/topics/options"
payload = { "filters": {
"sourceIds": ["<string>"],
"dimensions": [
{
"dimension": "<string>",
"operator": "<string>",
"values": ["<string>"]
}
]
} }
headers = {
"X-CB-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-CB-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
filters: {
sourceIds: ['<string>'],
dimensions: [{dimension: '<string>', operator: '<string>', values: ['<string>']}]
}
})
};
fetch('https://api.closebot.com/analytics/topics/options', 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://api.closebot.com/analytics/topics/options",
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([
'filters' => [
'sourceIds' => [
'<string>'
],
'dimensions' => [
[
'dimension' => '<string>',
'operator' => '<string>',
'values' => [
'<string>'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-CB-KEY: <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://api.closebot.com/analytics/topics/options"
payload := strings.NewReader("{\n \"filters\": {\n \"sourceIds\": [\n \"<string>\"\n ],\n \"dimensions\": [\n {\n \"dimension\": \"<string>\",\n \"operator\": \"<string>\",\n \"values\": [\n \"<string>\"\n ]\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-CB-KEY", "<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://api.closebot.com/analytics/topics/options")
.header("X-CB-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"filters\": {\n \"sourceIds\": [\n \"<string>\"\n ],\n \"dimensions\": [\n {\n \"dimension\": \"<string>\",\n \"operator\": \"<string>\",\n \"values\": [\n \"<string>\"\n ]\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.closebot.com/analytics/topics/options")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-CB-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"filters\": {\n \"sourceIds\": [\n \"<string>\"\n ],\n \"dimensions\": [\n {\n \"dimension\": \"<string>\",\n \"operator\": \"<string>\",\n \"values\": [\n \"<string>\"\n ]\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"topics": [
{
"topicId": "<string>",
"name": "<string>",
"slug": "<string>",
"conversationCount": 123
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>"
}
