Get Aggregate
curl --request GET \
--url https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate', 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.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate",
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://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate"
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://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate")
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{
"true_count": 123,
"false_count": 123,
"null_count": 123,
"error_count": 123,
"type": "boolean",
"timeseries": []
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Post-Call Variables
Aggregate Extraction Field
Type-discriminated aggregation of a single post-call extraction field across the filtered window.
GET
/
api
/
v1
/
analytics
/
post-call-variables
/
aggregate
Get Aggregate
curl --request GET \
--url https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate', 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.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate",
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://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate"
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://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate")
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{
"true_count": 123,
"false_count": 123,
"null_count": 123,
"error_count": 123,
"type": "boolean",
"timeseries": []
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Compute an aggregate for one extraction field across the filtered window. The response shape is discriminated on the field’s
type — boolean, selector, number, or text.
GET /api/v1/analytics/post-call-variables/aggregate
Query parameters
string
required
Comma-separated workflow ids. See Overview → Single vs. cross-workflow mode. In cross mode,
field_name must appear on every requested workflow.string
required
Field name as defined in the workflow’s extraction schema. Not found →
400.string (ISO 8601)
Start of the window (inclusive). Defaults to
to - 30 days.string (ISO 8601)
End of the window (exclusive). Defaults to now.
string
default:"day"
Time bucket for the
timeseries array. One of hour, day, week, month. Ignored for text fields (no timeseries).integer
default:"10"
Number of equal-width histogram buckets for
number fields (capped at 50 per spec).integer
default:"20"
Number of top values to return for
text fields (capped at 100 per spec).string
Optional chart-type hint used for validation. The server rejects a hint that isn’t in the allowed set for the field’s type (see the mapping in
openspec/changes/post-call-variable-charts/design.md §D1).Call-attribute filters
All optional. See Overview → Call-attribute filters.string
string
string
string
boolean
boolean
boolean
string
Response
The response is a discriminated union ontype. Every variant includes null_count and error_count so extraction failures are visible and never silently folded into a headline number.
type: "boolean"
integer
integer
integer
Runs where the field was expected but the value was
null.integer
Runs where extraction itself raised an error.
array
type: "selector"
object
Map of option label → count over the window.
integer
integer
type: "number"
integer
integer
type: "text"
integer
Number of distinct non-null values in the window. Compare against
total_count to detect long-tail free-text extractions (distinct_count / total_count > 0.8 = top-N is not meaningful).integer
Non-null value count in the window.
integer
integer
integer
Echo of the requested
top_n.Example — boolean
cURL
curl "https://api.peachdeskai.com/api/v1/analytics/post-call-variables/aggregate?workflow_ids=42&field_name=qualified&granularity=day&from=2026-07-01T00:00:00Z&to=2026-08-01T00:00:00Z" \
-H "X-API-Key: $PEACHDESK_API_KEY"
Response
{
"type": "boolean",
"true_count": 128,
"false_count": 302,
"null_count": 14,
"error_count": 3,
"timeseries": [
{ "bucket": "2026-07-30T00:00:00Z", "true_pct": 0.31, "n": 42 },
{ "bucket": "2026-07-31T00:00:00Z", "true_pct": 0.28, "n": 39 }
]
}
Example — selector
Response
{
"type": "selector",
"option_counts": { "price": 47, "product": 22, "support": 18, "other": 6 },
"null_count": 9,
"error_count": 1,
"timeseries": [
{ "bucket": "2026-07-31T00:00:00Z", "option_counts": { "price": 8, "product": 3 } }
]
}
Example — number
Response
{
"type": "number",
"histogram": [
{ "bucket_min": 0, "bucket_max": 100, "count": 12 },
{ "bucket_min": 100, "bucket_max": 200, "count": 33 },
{ "bucket_min": 200, "bucket_max": 300, "count": 21 }
],
"stats": {
"min": 15, "max": 285, "avg": 168.4, "p50": 175, "p95": 262, "n": 66
},
"null_count": 4,
"error_count": 0,
"timeseries": [
{ "bucket": "2026-07-30T00:00:00Z", "avg": 172.1, "n": 22 }
]
}
Example — text
Response
{
"type": "text",
"top_values": [
{ "value": "cancel my plan", "count": 12 },
{ "value": "reset password", "count": 9 }
],
"distinct_count": 47,
"total_count": 60,
"null_count": 5,
"error_count": 1,
"top_n": 20
}
Errors
| Status | When |
|---|---|
400 | Unknown field_name on any requested workflow. |
400 | chart_type is not allowed for the resolved field type. |
400 | granularity is not one of hour/day/week/month. |
400 | from > to. |
400 | workflow_ids missing, empty, or contains a non-integer id. |
404 | Any workflow_id does not belong to the caller’s organization. |
Authorizations
SessionAuthApiKeyAuth
Interactive user session: the login JWT, sent as Authorization: Bearer <token>.
Query Parameters
Required range:
x >= 1Required range:
x >= 1Required range:
1 <= x <= 20Required range:
0 <= x <= 1Response
Successful Response
- BooleanAggregate
- SelectorAggregate
- NumberAggregate
- TextAggregate
- TextWordFrequencyAggregate

