Skip to content
Dashboard

Query syntax reference

The full reporting query grammar – metrics, aggregations, filters, grouping, comparison windows and drill-ins.

Every report query is a JSON body sent to POST /v2/reports/query. This page documents the complete grammar. The datasets catalog (GET /v2/reports/datasets) is the authoritative source for the metric and attribute IDs your workspace accepts.

{
"metric": "new_conversations",
"aggregation": "count",
"startDate": "2026-06-01",
"endDate": "2026-06-30",
"compareStartDate": "2026-05-01",
"compareEndDate": "2026-05-31",
"granularity": "day",
"timezone": "Europe/Tallinn",
"officeHoursOnly": false,
"filters": { "kind": "rule", "fieldId": "conversation.channel", "operator": "is", "value": "email" },
"groupBy": "teammate.currently_assigned",
"segmentBy": "conversation.priority",
"view": "standard"
}
FieldRequiredDescription
metricyesMetric ID from the catalog
aggregationyesOne of the metric’s allowedAggregations
percentilewith percentile aggregation1–100, e.g. 95 for p95
startDate / endDateyesISO 8601 date or datetime, inclusive window
compareStartDate / compareEndDatenoComparison window – adds previousValue and deltaPercent to every datum
granularityyeshour, day, week or month – the time-series bucket size
timezonenoIANA timezone for bucketing (defaults to UTC)
officeHoursOnlynoRestrict time metrics to configured office hours (only metrics with supportsOfficeHours)
filtersnoFilter expression (see below)
groupBynoAttribute ID for the primary breakdown
segmentBynoAttribute ID for a secondary breakdown within each group/bucket
viewnostandard (default), hourly_heatmap or sankey
AggregationUse with
countCount metrics (new_conversations, replies_sent, …)
avg, median, min, maxDuration and number metrics
percentileDuration metrics – pass percentile: 95 alongside
sumSummable number metrics
valueRate/percentage metrics (csat_score, reopen_rate, …)

Each metric lists its own allowedAggregations in the catalog; anything else returns 400 invalid_parameter.

A filter is either a single rule or a group combining child expressions with and / or. Groups nest up to 6 levels; 100 rules max per expression.

FilterExpression := Rule | Group
Rule := { "kind": "rule", "fieldId": string, "operator": Operator, "value"?: Value }
Group := { "kind": "group", "op": "and" | "or", "children": FilterExpression[] }
Value := string | number | boolean | Array<string | number | boolean>

Example – email or web-chat conversations that are closed:

{
"kind": "group",
"op": "and",
"children": [
{ "kind": "rule", "fieldId": "conversation.channel", "operator": "in", "value": ["email", "desktop"] },
{ "kind": "rule", "fieldId": "conversation.state", "operator": "is", "value": "closed" }
]
}
OperatorMeaningValue shape
is / is_notEqualityscalar
in / not_inSet membershipnon-empty array
contains / not_containsSubstring / multi-value containmentscalar
gte / lteGreater/less than or equalscalar (number, or ISO date string for date attributes)
betweenInclusive range2-element array
exists / not_existsAttribute has any valueomit value
is_member_of / is_not_member_ofMembership in a referenced set (e.g. team)non-empty array

Wrong value shape for an operator returns 400 with a message naming the operator and field.

Attributes are scoped to datasets: filters, groupBy and segmentBy must use attributes from the same dataset as the metric. Find the metric’s dataset in GET /v2/reports/datasets (the dataset whose metrics array contains it — also echoed as meta.datasetId in query responses) and pick from that dataset’s attributes. Each attribute lists its allowedOperators, valueType and supportsFilter / supportsGroupBy flags.

For valid values: attributes with staticOptions carry their full value set inline; for the rest use POST /v2/reports/filter-values:

{ "fieldId": "conversation.tags", "query": "bill", "limit": 20 }
  • groupBy breaks the aggregate down by one attribute → groupedData in the response
  • segmentBy adds a second dimension → segments arrays nested inside each group and time-series datum

Attributes must have supportsGroupBy: true in the catalog. Group values come back as raw values (group) plus display labels (groupLabel) where the raw value is an ID.

Pass compareStartDate / compareEndDate (both or neither). Every datum then carries previousValue, and the top level adds deltaPercent. Typical usage is the same-length window immediately before startDate.

Each metric lists its supportedViews in the catalog.

  • standard – time series + optional groups/segments (default)
  • hourly_heatmap – buckets by day-of-week × hour-of-day; drill in with dayOfWeek (1 = Monday) + hourOfDay (0–23)
  • sankey – conversation flow edges in flowData (overview_conversation_flow metric only); drill in with flowPathId or sourceNodeId + targetNodeId
{
"object": "report_query_result",
"value": 1284,
"previousValue": 1120,
"deltaPercent": 14.6,
"timeSeries": [ { "date": "2026-06-01", "value": 43, "previousValue": 39 } ],
"groupedData": [ { "group": "email", "groupLabel": "Email", "value": 612 } ],
"meta": {
"metric": "new_conversations",
"datasetId": "conversations",
"unit": "count",
"granularity": "day",
"aggregation": "count",
"officeHoursOnly": false
}
}

Duration values are milliseconds (unit: "duration_ms"); percentages are 0–100 (unit: "percentage").

POST /v2/reports/drill-in returns the paginated rows behind a metric. Send the same query context (metric, dates, granularity, filters, groupBy, segmentBy, view) plus dataPointFilters selecting the point:

Data pointdataPointFilters
Whole window{}
One time bucket{ "timeBucket": "2026-06-15" }
One group{ "groupValue": "email" }
Heatmap cell{ "dayOfWeek": 2, "hourOfDay": 14 }
Flow edge{ "sourceNodeId": "...", "targetNodeId": "..." }

Pagination is page (1-based) + pageSize (max 200). The response lists availableColumns (all columns the dataset offers) and defaultColumnIds; rows are keyed by column ID. Cells holding people (teammates, contacts) are identity objects: { "kind": "identity", "id": "...", "label": "..." }. Sort with sort: [{ "fieldId": "metric.value", "direction": "desc" }].

StatusCodeCause
400invalid_parameterUnknown metric/attribute, disallowed aggregation or operator, malformed filter
404resource_not_foundReports not enabled for the workspace
400validation messageBody fails schema validation (unknown keys are rejected)