GET /v1/analytics/schema lists every metric you can query and what each one supports, so an agent can build a valid query on the first try.
Quickstart
Calls per day over the last week, and the average sentiment score:- Node
- Python
- CLI
- cURL
metric:read permission. A read-only key is enough: a query never changes anything.
What you can query
Read the schema first. It lists the project’s metrics by slug, each with its output type, its default aggregation and the aggregations it supports, plus every filter and breakdown type and the custom call properties seen in the project.Measures
A query has one to ten measures: the things to aggregate.
Set
aggregation to choose another: AVG, MIN, MAX, SUM, MEDIAN, PERCENTILE (with percentile, e.g. 95), COUNT or PASS_RATE. The schema lists which ones each metric supports, and a query asking for one it doesn’t support returns 400 saying which to use instead.
- Per call first. Metric values are folded to one value per call before they are aggregated (
distinctBy: CALL), so a long call with many scored segments doesn’t outweigh a short one. SetdistinctBy: NONEto aggregate every value. - Pass rates.
PASS_RATEis the share of calls that meet a condition, from 0 to 1:{ "metric": "response_time", "aggregation": "PASS_RATE", "passOperator": "LESS_THAN", "passValue": 800 }. A threshold metric already carries its condition, so querying it by slug gives its pass rate directly.sampleSizeis the number of calls evaluated;0means no data, not 0%. - Units. Values come back in the metric’s display units.
Time windows
timeRange picks the window. It defaults to the last 30 days, and covers at most two years.
timezone (an IANA name such as America/New_York, default UTC) decides where days, weeks and calendar periods start. interval (HOUR, DAY, WEEK, MONTH) sets the bucket size; leave it out and it is chosen from the window’s length. A window that would produce more than 500 buckets steps to a coarser interval. Set includeBuckets: false to get totals only.
Filters, breakdowns and comparisons
Filters narrow what is counted. Top-levelfilters apply to every measure; a measure’s own filters add to them.
operator defaults to EQUALS; the others are NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL_TO, LESS_THAN, LESS_THAN_OR_EQUAL_TO, CONTAINS and STARTS_WITH. The schema lists every filter type and the properties each accepts.
Breakdowns split a measure into one series per value. { "metric": "sentiment_score", "breakdown": { "type": "AGENT_PROPERTY" } } returns sentiment per agent; { "type": "CALL_PROPERTY", "property": "direction" } splits by inbound and outbound. The 50 largest series are returned, and omittedSeries counts the rest.
Comparisons:
comparisonMode: "PREVIOUS_PERIOD"adds the preceding window of the same length to every series (comparisonValue, and per bucket).comparisonGroupsruns every measure once per named filter set, for example one group per agent or per region (2 to 5 groups). While groups are set, breakdowns are ignored: each group is one series.
The response
measureIndex points back to the measure in your request. value is the aggregate over the whole window, and buckets holds the per-interval values.
A query the analytics store can’t answer returns 400 naming the part it can’t, never unfiltered numbers. An unknown metric slug returns 404.
From a query to a dashboard
A dashboard widget is a query plus a name, a chart type and a size. Once a query answers the question, save it as a widget withPOST /v1/dashboard/{dashboardId}/widget, or declare the dashboard in config as code.
Dashboards
Save queries as widgets and read them back over the API
Dashboards as code
Define dashboards in YAML next to the rest of your config