Get Statistics
curl --request GET \
--url https://api.example.com/v1/statsimport requests
url = "https://api.example.com/v1/stats"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/stats', 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.example.com/v1/stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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.example.com/v1/stats"
req, _ := http.NewRequest("GET", url, nil)
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.example.com/v1/stats")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyStatistics
Get Statistics
Returns the same numbers as the Statistics page of the app, for any period, with filters and breakdowns.
GET
/
v1
/
stats
Get Statistics
curl --request GET \
--url https://api.example.com/v1/statsimport requests
url = "https://api.example.com/v1/stats"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/stats', 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.example.com/v1/stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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.example.com/v1/stats"
req, _ := http.NewRequest("GET", url, nil)
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.example.com/v1/stats")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyGet Statistics
Returns totals for your account and optional breakdowns by day, campaign, agent, disposition or workspace. The numbers are calculated exactly like the Statistics page of the app. By default: last 7 days, outbound and inbound calls together, timezoneEurope/Paris. Days are calendar days in the chosen timezone and the end day is included.
Request
GET /v1/stats
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
period | string | No | Preset period: today, yesterday, this_week, last_week, this_month, last_month, last_7_days, last_30_days, all_time (default: last_7_days) |
date_from | string | No | Custom start day (YYYY-MM-DD, included). Cannot be combined with period |
date_to | string | No | Custom end day (YYYY-MM-DD, included). Defaults to today |
timezone | string | No | Timezone used to cut days, as an IANA name (default: Europe/Paris) |
direction | string | No | all (default), outbound or inbound |
campaign_id | string | No | Only count these campaigns. One UUID or several separated by commas (max 50) |
agent_id | uuid | No | Only count calls made or received by this agent |
workspace_id | string | No | Only count this workspace. Use none for calls outside any workspace |
group_by | string | No | Breakdowns to include, separated by commas: day, campaign, agent, disposition, workspace |
Example
curl -X GET \
"https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/stats?period=last_7_days&group_by=day,campaign,agent,disposition,workspace" \
-H "Authorization: Bearer rchd_live_xxxxxxxxxxxx"
const params = new URLSearchParams({
period: "last_7_days",
group_by: "day,campaign,agent,disposition,workspace"
});
const response = await fetch(
`https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/stats?${params}`,
{
headers: {
"Authorization": "Bearer rchd_live_xxxxxxxxxxxx"
}
}
);
const { data } = await response.json();
import requests
response = requests.get(
"https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/stats",
headers={"Authorization": "Bearer rchd_live_xxxxxxxxxxxx"},
params={
"period": "last_7_days",
"group_by": "day,campaign,agent,disposition,workspace"
}
)
data = response.json()["data"]
Custom date range for one agent
curl -X GET \
"https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/stats?date_from=2026-03-01&date_to=2026-03-15&agent_id=u1a2b3c4-...&direction=outbound" \
-H "Authorization: Bearer rchd_live_xxxxxxxxxxxx"
const params = new URLSearchParams({
date_from: "2026-03-01",
date_to: "2026-03-15",
agent_id: "u1a2b3c4-...",
direction: "outbound"
});
const response = await fetch(
`https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/stats?${params}`,
{ headers: { "Authorization": "Bearer rchd_live_xxxxxxxxxxxx" } }
);
const { data } = await response.json();
Response
- 200 OK
- 400 Bad Request
{
"data": {
"period": {
"preset": "last_7_days",
"date_from": "2026-03-14",
"date_to": "2026-03-21",
"timezone": "Europe/Paris"
},
"filters": {
"direction": "all",
"campaign_ids": null,
"agent_id": null,
"workspace_id": null
},
"totals": {
"total_calls": 412,
"sessions": 300,
"calls_per_session": 1.37,
"connected_calls": 96,
"connection_rate": 32.0,
"conversations": 41,
"appointments": 9,
"conversion_rate": 9.4,
"talk_time_seconds": 9540,
"avg_talk_time_seconds": 92,
"voicemails_reached": 38,
"voicemails_avoided": 71,
"called_leads": 280,
"callback_leads": 18,
"callback_rate": 6.4
},
"breakdowns": {
"day": [
{ "date": "2026-03-20", "total_calls": 75, "sessions": 54, "connected_calls": 18, "connection_rate": 33.3, "conversations": 8, "appointments": 2 }
],
"campaign": [
{ "campaign_id": "c1d2e3f4-...", "campaign_name": "Q1 Outreach", "total_calls": 398, "sessions": 290, "connected_calls": 92 },
{ "campaign_id": null, "campaign_name": "Calls without campaign", "total_calls": 14, "sessions": 10, "connected_calls": 4 }
],
"agent": [
{ "agent_id": "u1a2b3c4-...", "agent_name": "Sophie Bernard", "agent_email": "sophie@company.com", "total_calls": 210 },
{ "agent_id": null, "agent_name": "Unassigned", "agent_email": null, "total_calls": 3 }
],
"workspace": [
{ "workspace_id": "w1x2y3z4-...", "workspace_name": "Paris team", "total_calls": 300 },
{ "workspace_id": null, "workspace_name": "Default workspace", "total_calls": 112 }
],
"disposition": [
{ "disposition": "no-answer", "label_en": "No Answer", "label_fr": "Pas de réponse", "calls": 214, "percentage": 51.9 },
{ "disposition": "appointment-scheduled", "label_en": "Appointment Scheduled", "label_fr": "Rendez-vous pris", "calls": 9, "percentage": 2.2 }
]
}
}
}
{
"error": {
"code": "bad_request",
"message": "Use either period or date_from/date_to, not both."
}
}
The example above is shortened. Each line of the
day, campaign, agent and workspace breakdowns contains the same metrics as totals. A breakdown is only returned when it is requested in group_by.Top-level Fields
| Field | Type | Description |
|---|---|---|
period | object | The period actually used: preset (or null for a custom range), date_from, date_to, timezone |
filters | object | The filters actually applied: direction, campaign_ids, agent_id, workspace_id |
totals | object | Metrics for everything matching the period and filters |
breakdowns | object | The breakdowns requested in group_by |
Metrics
| Field | Type | Description |
|---|---|---|
total_calls | integer | Every line dialed |
sessions | integer | Dialing attempts. With parallel dialing, several lines dialed together count as one session |
calls_per_session | float | total_calls / sessions |
connected_calls | integer | Sessions where a real person was put through to the agent (voicemails and answering machines excluded) |
connection_rate | float | connected_calls / sessions, in % |
conversations | integer | Connected calls lasting 60 seconds or more |
appointments | integer | Calls with the appointment-scheduled disposition |
conversion_rate | float | appointments / connected_calls, in % |
talk_time_seconds | integer | Time spent talking on connected calls |
avg_talk_time_seconds | integer | Average talk time per connected call |
voicemails_reached | integer | Calls that ended on a voicemail (voicemail, voicemail-left) |
voicemails_avoided | integer | Voicemails or answering machines detected and skipped automatically |
called_leads | integer | Distinct leads called at least once |
callback_leads | integer | Called leads who called back afterwards |
callback_rate | float | callback_leads / called_leads, in % |
Breakdowns
| Breakdown | Identifying fields | Notes |
|---|---|---|
day | date | One line per calendar day in the chosen timezone |
campaign | campaign_id, campaign_name | Calls without a campaign appear on a Calls without campaign line (campaign_id: null) |
agent | agent_id, agent_name, agent_email | Calls without an agent appear on an Unassigned line (agent_id: null) |
workspace | workspace_id, workspace_name | Calls outside any workspace appear on a Default workspace line (workspace_id: null) |
disposition | disposition, label_en, label_fr | Contains calls and percentage (share of total_calls) instead of the full metrics |
Errors
| Status | Code | Description |
|---|---|---|
400 | bad_request | Invalid period, dates, timezone, direction, filter or group_by value |
401 | unauthorized | Missing or invalid API key |
500 | internal | Unexpected server error |
To get the statistics of a single campaign with its per-agent performance, you can also use Get Campaign Statistics. To go down to individual calls, use List Call Logs.
.png?fit=max&auto=format&n=PYj-p9lRwfHX4QQS&q=85&s=967f00940a17d1d8cc11bd8995dc98d0)
.png?fit=max&auto=format&n=PYj-p9lRwfHX4QQS&q=85&s=5072033d90dfd5e7cc9349712ea4e145)