POST /reports only reads data. It uses POST because the request is a JSON body.
Find the metric for your question
Read these definitions before you put a number in front of anyone. AI-resolved, for example, does not mean the customer’s problem was solved.
Run a report
Request body
string
required
The time window, in your team’s timezone:
today,yesterday,7d,14d,30d,90d,365d,mtd, orytd.month, withmonthset to a calendar month.custom, withfromandtoset. Up to 366 days.
today counts. 30d starts 30 days ago at the current time of day in your team’s timezone, and ends now. On October 6, the response’s range shows from 2026-09-06 and to 2026-10-06: 31 dates, the first and last of them partial. The other day ranges work the same way. For whole days, use custom.string
YYYY-MM. Required when range is month.string
YYYY-MM-DD, the first day. Required when range is custom.string
YYYY-MM-DD, the last day, included. Required when range is custom.string
Break the numbers into rows. One of
day, week, month, hour_of_day, category, channel, phone_line, team_member, task_age, action_group, failure_type, failure_subcategory, or cancellation_reason. Each metric supports only some of them. See the catalog.hour_of_dayreturns 24 rows, labeled00:00to23:00, by the hour each conversation started in your team’s timezone. It works withinclude_percent_of_totalbut not withtop_n.task_ageworks only withopen_tasks. It returns four rows by the time since the conversation or form came in:Under 1 day,1 to 3 days,3 to 7 days, and7 days or more.
string
team_member. Splits one team-work metric (tasks_worked or task_closes) by team member over time. Requires group_by of day or week.object
Narrow the data.
integer
1 to 10. Keep only the largest rows of a category-style breakdown, such as
category, team_member, or cancellation_reason. For category, the rest go into one All other categories row. Any other grouping returns unsupported_combination. Without top_n, team_member_activity and account_updates return their top 5 rows.boolean
Add
percent_of_total to each row of a category-style or channel breakdown. One grouped count metric at a time.Response
string
ok when the report ran. See Unsupported requests for the other values.object
The window the report used: the
requested range, the from and to dates (both included), and the team timezone.object
One entry for each requested metric, keyed by metric. Each entry has a
label, a unit (count, percent, minutes, hours, or score), and a value, which is null when there is no data. Rates also include numerator and denominator. A count with a natural base, such as memberships_saved, also has numerator, denominator, and rate. A percent value or rate runs from 0 to 100, rounded to one decimal place.object[]
The breakdown, when there is one. Each row has a
label and values, usually keyed by metric. Only metrics that support the grouping appear in values. A metric with a null value has no data for that row.A row grouped by channel, category, phone_line, or team_member also has that key, next to label:channel: a channel, such asphone.category: a category key, such ascancellation.nullon theUncategorizedandAll other categoriesrows.phone_line: the line’sid,name, andphone_number.team_member: the person’sidandname.nullon theUnassignedrow.
label is for display.A few breakdowns use other keys in values. team_member_activity uses tasks_completed, messages_sent, and notes_added. account_updates uses account_updates, completed, and failures. conversation_categories by phone_line uses Total plus one key for each category label. split_by uses team member names.Count metrics that support day get a trend in rows even without group_by: daily for ranges up to 31 days, weekly beyond that. Ranges today and yesterday get no trend.string
The grouping the rows use. It can differ from your
group_by. A daily series longer than 62 days comes back weekly.object
The chart the dashboard draws from the rows:
kind (line or bar), title, label_kind, and up to five series of points. Absent when the rows cannot be charted.string[]
How each metric is counted. Read these before you compare numbers with another system.
string[]
Anything that limits this result, such as missing history or overlapping rows.
string
The dashboard Reports page.
Unsupported requests
The catalog limits which metrics, groupings, and filters go together. A request outside those limits returnsstatus set to unsupported_combination, with a reason, a message, and the allowed_alternatives you can retry with.
filters.team_member_ids that is not a current team member returns reason set to unknown_team_member, with a message that lists the IDs.
These responses come back with HTTP 200, not a 4xx. A client that checks only the HTTP status treats them as success. Check status before you read values. A missing month, from, or to, or a custom range that is reversed or longer than 366 days, is also an unsupported_combination. A malformed body returns 400. That includes an unknown metric key and any field the API does not know, such as grouping or filters.phone_number_id. A filters.phone_line_id that is not one of the key owner’s phone lines returns 404 with code not_found.
Read these definitions first
Several metrics mean something narrower than their name. Themethodology in each response says exactly what was counted.
- AI-resolved (
ai_resolved_conversations) means nobody on your team replied, changed the task, or added a note. It does not mean the customer’s problem was solved. For that, usecaller_resolved_rate. - Meaningful conversations (
meaningful_conversations) have enough real exchange to judge how they went: phone calls longer than 10 seconds with a transcript where the caller said enough, and website chats with a real exchange or a follow-up task. Texts and emails are never counted. - Handled (
handled_conversations) means a meaningful conversation that left no task for your team. Needs team (needs_team_conversations) means a meaningful conversation that did leave one. Handled does not mean the customer’s problem was solved. - Hours to close and hours to first action count elapsed hours from when the conversation or form came in. They are not business hours or time spent working.
- First action is the first time a person changed a task’s status or assignee, added a note, sent a reply, or closed it. Creating the task does not count. Because assignment and notes count, hours to first action is not a customer response time. Tasks nobody has acted on are left out of the hours-to-first-action metrics. To see those, run
open_taskswithgroup_bytask_age. - Asked for a person, resolved by AI (
asked_for_person_ai_resolved_conversations) counts conversations where the customer asked for a person, the caller’s need was met, nobody on your team worked it, and the AI attempted no transfer. - Transfer attempts (
transfer_attempts) count conversations where the AI tried to transfer the caller. A transfer attempt does not mean a person answered. - Tasks completed (
tasks_completed) counts tasks marked done, including tasks the AI closed on its own. To count closes by people, usetask_closes. - Team-work metrics (
tasks_worked,task_closes, the hours-to-close and hours-to-first-action metrics,same_day_close_rate, andopen_tasks) have data from July 25, 2026. A range that ends before then returnsunsupported_combination. - Memberships saved (
memberships_saved) counts only cancellation conversations where the AI pitched a retention offer and the membership was saved. A save with no retention offer pitched is not counted. It counts from July 1, 2026, when save tracking started. Itsdenominatoris the cancellation conversations with a retention offer pitched in the same period. - Open tasks right now (
open_tasks) is a snapshot. It requiresrangetoday.
Examples
AI-resolved rate by week
ai_resolved_rate has no weekly breakdown. Request the two counts by week and divide them. The headline rate for the whole range comes back in values.
chart field is left out of this example and the ones below.
Tasks closed per team member, with median hours to close
Retention offers pitched and accepted
rows. For one location, add "filters": { "phone_line_id": 2181 }. To see why customers cancel, run cancellation_reasons with group_by set to cancellation_reason.
Conversations by phone line
phone_line.id. The label is the line name, and when two lines share a name it adds the phone number. The phone channel filter limits the report to calls. Leave it out to count texts, chats, and emails too. For a metric that does not group by phone line, run one report per line with filters.phone_line_id.
Calls per hour
To find your busiest hours, groupconversations by hour_of_day and filter to phone calls.
"include_percent_of_total": true to get each hour’s share of the day’s calls.
List the metrics
requires_group_by is true, the metric fails without one of its group_by values. categories lists every category key with its label. filters maps each filter name to its JSON Schema. The example shortens measures, categories, and filters.
Metric catalog
Fifty-four metrics as of October 2026. The table is generated from the same code asGET /reports/metrics. A metric with no group_by returns only a total. “Required” means the metric needs one of the listed groupings. Read these definitions first for the terms in the Description column.
Conversations and calls
Call quality (phone calls only)
Cancellations and offers
Tasks
Team work
group_by month covers at most 12 calendar months. With team_member, the hours-to-first-action metrics credit the person who acted first. For average call length, run avg_duration_minutes with filters.channel set to phone.