Skip to content
Dashboard

Reports

Query your workspace analytics: conversation volume, response times, CSAT, SLA compliance, teammate performance, AI agent resolutions and more. Start with the datasets catalog to discover metrics and attributes, then run queries with filters, grouping and period comparison.

List report datasets
client.reports.listDatasets(ReportListDatasetsParams { featurebaseVersion } params?, RequestOptionsoptions?): ReportListDatasetsResponse { data, object }
GET/v2/reports/datasets
Run a report query
client.reports.query(ReportQueryParams { aggregation, endDate, granularity, 16 more } params, RequestOptionsoptions?): ReportQueryResponse { meta, object, value, 7 more }
POST/v2/reports/query
Look up report filter values
client.reports.lookupFilterValues(ReportLookupFilterValuesParams { fieldId, limit, query, 2 more } params, RequestOptionsoptions?): ReportLookupFilterValuesResponse { data, object }
POST/v2/reports/filter-values
Drill into report rows
client.reports.drillIn(ReportDrillInParams { endDate, granularity, metric, 16 more } params, RequestOptionsoptions?): ReportDrillInResponse { availableColumns, defaultColumnIds, meta, 6 more }
POST/v2/reports/drill-in
ModelsExpand Collapse
ReportAttribute { id, allowedOperators, category, 9 more }
id: string

Attribute ID — use as fieldId in filter rules and as groupBy / segmentBy in query requests.

allowedOperators: Array<"is" | "is_not" | "in" | 10 more>
One of the following:
"is"
"is_not"
"in"
"not_in"
"contains"
"not_contains"
"gte"
"lte"
"between"
"exists"
"not_exists"
"is_member_of"
"is_not_member_of"
category: string
description: string
name: string
semantics: "current_state" | "historical_action" | "historical_snapshot" | "dynamic_metric_mapped"

Whether the filter uses the latest mutable state, an immutable historical action/snapshot, or a metric-dependent mapping.

One of the following:
"current_state"
"historical_action"
"historical_snapshot"
"dynamic_metric_mapped"
supportsFilter: boolean

Whether the attribute can be used in filters rules.

supportsGroupBy: boolean

Whether the attribute can be used as groupBy / segmentBy.

supportsValueLookup: boolean

Whether POST /v2/reports/filter-values can list this attribute’s values.

valueType: "string" | "number" | "boolean" | 3 more
One of the following:
"string"
"number"
"boolean"
"date"
"enum"
"id"
multiValue?: boolean
staticOptions?: Array<ReportAttributeOption { label, value } >

Fixed value set for enum-like attributes. Attributes without static options resolve values via POST /v2/reports/filter-values.

label: string
value: string
ReportAttributeOption { label, value }
label: string
value: string
ReportDataset { id, attributes, description, 2 more }
id: string
attributes: Array<ReportAttribute { id, allowedOperators, category, 9 more } >
id: string

Attribute ID — use as fieldId in filter rules and as groupBy / segmentBy in query requests.

allowedOperators: Array<"is" | "is_not" | "in" | 10 more>
One of the following:
"is"
"is_not"
"in"
"not_in"
"contains"
"not_contains"
"gte"
"lte"
"between"
"exists"
"not_exists"
"is_member_of"
"is_not_member_of"
category: string
description: string
name: string
semantics: "current_state" | "historical_action" | "historical_snapshot" | "dynamic_metric_mapped"

Whether the filter uses the latest mutable state, an immutable historical action/snapshot, or a metric-dependent mapping.

One of the following:
"current_state"
"historical_action"
"historical_snapshot"
"dynamic_metric_mapped"
supportsFilter: boolean

Whether the attribute can be used in filters rules.

supportsGroupBy: boolean

Whether the attribute can be used as groupBy / segmentBy.

supportsValueLookup: boolean

Whether POST /v2/reports/filter-values can list this attribute’s values.

valueType: "string" | "number" | "boolean" | 3 more
One of the following:
"string"
"number"
"boolean"
"date"
"enum"
"id"
multiValue?: boolean
staticOptions?: Array<ReportAttributeOption { label, value } >

Fixed value set for enum-like attributes. Attributes without static options resolve values via POST /v2/reports/filter-values.

label: string
value: string
description: string
metrics: Array<ReportMetric { id, allowedAggregations, description, 13 more } >
id: string

Metric ID — use as metric in query requests.

allowedAggregations: Array<"count" | "sum" | "avg" | 6 more>
One of the following:
"count"
"sum"
"avg"
"median"
"min"
"max"
"range"
"percentile"
"value"
description: string
name: string
supportedFilterAttributeIds: Array<string>

Attribute IDs this specific metric accepts in filter expressions.

supportedGroupByDimensions: Array<string>

Attribute IDs this specific metric accepts as groupBy or segmentBy.

supportedViews: Array<"standard" | "hourly_heatmap" | "sankey">

Which view values POST /v2/reports/query accepts for this metric. Most metrics support standard and hourly_heatmap; conversation-flow metrics are sankey-only.

One of the following:
"standard"
"hourly_heatmap"
"sankey"
supportsOfficeHours: boolean
supportsPeriodComparison: boolean
type: "count" | "percentage" | "duration" | "number"
One of the following:
"count"
"percentage"
"duration"
"number"
unit: "count" | "percentage" | "duration_ms" | "number"
One of the following:
"count"
"percentage"
"duration_ms"
"number"
dataAvailableFromIso?: string

Local calendar date (ISO 8601) from which this specific metric has data, when it differs from the global reporting floor. Windows ending before this date are rejected for this metric.

isDefaultVariant?: boolean

Whether this variant is the default selection for its variantGroupId.

variantGroupId?: string

Metrics sharing a variantGroupId are timestamp variants of one logical metric (same display name); each measures the same population at a different timestamp. Query the concrete metric id to pick a variant.

variantId?: string

Stable identifier for this variant within its group (e.g. created_at, started_at).

variantLabel?: string

Human-readable variant label for pickers (e.g. Created at, Started at).

name: string
ReportFilterExpression { children, kind, op }
children: Array<ReportFilterRule { fieldId, kind, operator, value } | ReportFilterGroup { children, kind, op } >

Rules and/or nested groups of rules. Groups may nest up to 6 levels at runtime; 100 rules max per expression.

One of the following:
ReportFilterRule { fieldId, kind, operator, value }
fieldId: string

Attribute ID to filter on (e.g. conversation.channel). Discover attribute IDs via GET /v2/reports/datasets.

minLength1
maxLength512
kind: "rule"
operator: "is" | "is_not" | "in" | 10 more

Comparison operator. Each attribute supports a subset of operators — see the allowedOperators field in the GET /v2/reports/datasets catalog.

One of the following:
"is"
"is_not"
"in"
"not_in"
"contains"
"not_contains"
"gte"
"lte"
"between"
"exists"
"not_exists"
"is_member_of"
"is_not_member_of"
value?: string | number | boolean | Array<string | number | boolean>

Value to compare against. Scalar for is, is_not, contains, not_contains, gte, lte (ISO date strings for date attributes); non-empty array for in, not_in, is_member_of, is_not_member_of; 2-element array for between; omit for exists / not_exists.

One of the following:
string
number
boolean
Array<string | number | boolean>
string
number
boolean
ReportFilterGroup { children, kind, op }
children: Array<ReportFilterRule { fieldId, kind, operator, value } >
fieldId: string

Attribute ID to filter on (e.g. conversation.channel). Discover attribute IDs via GET /v2/reports/datasets.

minLength1
maxLength512
kind: "rule"
operator: "is" | "is_not" | "in" | 10 more

Comparison operator. Each attribute supports a subset of operators — see the allowedOperators field in the GET /v2/reports/datasets catalog.

One of the following:
"is"
"is_not"
"in"
"not_in"
"contains"
"not_contains"
"gte"
"lte"
"between"
"exists"
"not_exists"
"is_member_of"
"is_not_member_of"
value?: string | number | boolean | Array<string | number | boolean>

Value to compare against. Scalar for is, is_not, contains, not_contains, gte, lte (ISO date strings for date attributes); non-empty array for in, not_in, is_member_of, is_not_member_of; 2-element array for between; omit for exists / not_exists.

One of the following:
string
number
boolean
Array<string | number | boolean>
string
number
boolean
kind: "group"
op: "and" | "or"

Group operator: and (all match) or or (any match).

One of the following:
"and"
"or"
kind: "group"
op: "and" | "or"

Group operator: and (all match) or or (any match).

One of the following:
"and"
"or"
ReportFilterRule { fieldId, kind, operator, value }
fieldId: string

Attribute ID to filter on (e.g. conversation.channel). Discover attribute IDs via GET /v2/reports/datasets.

minLength1
maxLength512
kind: "rule"
operator: "is" | "is_not" | "in" | 10 more

Comparison operator. Each attribute supports a subset of operators — see the allowedOperators field in the GET /v2/reports/datasets catalog.

One of the following:
"is"
"is_not"
"in"
"not_in"
"contains"
"not_contains"
"gte"
"lte"
"between"
"exists"
"not_exists"
"is_member_of"
"is_not_member_of"
value?: string | number | boolean | Array<string | number | boolean>

Value to compare against. Scalar for is, is_not, contains, not_contains, gte, lte (ISO date strings for date attributes); non-empty array for in, not_in, is_member_of, is_not_member_of; 2-element array for between; omit for exists / not_exists.

One of the following:
string
number
boolean
Array<string | number | boolean>
string
number
boolean
ReportGroupedDatum { group, value, groupLabel, 2 more }
group: string

Raw group value (e.g. an ID). Use groupLabel for display.

value: number
groupLabel?: string
previousValue?: number
segments?: Array<ReportSegmentDatum { segment, value, previousValue, segmentLabel } >
segment: string
value: number
previousValue?: number
segmentLabel?: string
ReportMetric { id, allowedAggregations, description, 13 more }
id: string

Metric ID — use as metric in query requests.

allowedAggregations: Array<"count" | "sum" | "avg" | 6 more>
One of the following:
"count"
"sum"
"avg"
"median"
"min"
"max"
"range"
"percentile"
"value"
description: string
name: string
supportedFilterAttributeIds: Array<string>

Attribute IDs this specific metric accepts in filter expressions.

supportedGroupByDimensions: Array<string>

Attribute IDs this specific metric accepts as groupBy or segmentBy.

supportedViews: Array<"standard" | "hourly_heatmap" | "sankey">

Which view values POST /v2/reports/query accepts for this metric. Most metrics support standard and hourly_heatmap; conversation-flow metrics are sankey-only.

One of the following:
"standard"
"hourly_heatmap"
"sankey"
supportsOfficeHours: boolean
supportsPeriodComparison: boolean
type: "count" | "percentage" | "duration" | "number"
One of the following:
"count"
"percentage"
"duration"
"number"
unit: "count" | "percentage" | "duration_ms" | "number"
One of the following:
"count"
"percentage"
"duration_ms"
"number"
dataAvailableFromIso?: string

Local calendar date (ISO 8601) from which this specific metric has data, when it differs from the global reporting floor. Windows ending before this date are rejected for this metric.

isDefaultVariant?: boolean

Whether this variant is the default selection for its variantGroupId.

variantGroupId?: string

Metrics sharing a variantGroupId are timestamp variants of one logical metric (same display name); each measures the same population at a different timestamp. Query the concrete metric id to pick a variant.

variantId?: string

Stable identifier for this variant within its group (e.g. created_at, started_at).

variantLabel?: string

Human-readable variant label for pickers (e.g. Created at, Started at).

ReportSegmentDatum { segment, value, previousValue, segmentLabel }
segment: string
value: number
previousValue?: number
segmentLabel?: string
ReportTimeSeriesDatum { date, value, previousValue, segments }
date: string

Time bucket start (ISO 8601).

value: number
previousValue?: number

Value for the same bucket in the comparison window, when requested.

segments?: Array<ReportSegmentDatum { segment, value, previousValue, segmentLabel } >
segment: string
value: number
previousValue?: number
segmentLabel?: string
ReportListDatasetsResponse { data, object }
data: Array<ReportDataset { id, attributes, description, 2 more } >
id: string
attributes: Array<ReportAttribute { id, allowedOperators, category, 9 more } >
id: string

Attribute ID — use as fieldId in filter rules and as groupBy / segmentBy in query requests.

allowedOperators: Array<"is" | "is_not" | "in" | 10 more>
One of the following:
"is"
"is_not"
"in"
"not_in"
"contains"
"not_contains"
"gte"
"lte"
"between"
"exists"
"not_exists"
"is_member_of"
"is_not_member_of"
category: string
description: string
name: string
semantics: "current_state" | "historical_action" | "historical_snapshot" | "dynamic_metric_mapped"

Whether the filter uses the latest mutable state, an immutable historical action/snapshot, or a metric-dependent mapping.

One of the following:
"current_state"
"historical_action"
"historical_snapshot"
"dynamic_metric_mapped"
supportsFilter: boolean

Whether the attribute can be used in filters rules.

supportsGroupBy: boolean

Whether the attribute can be used as groupBy / segmentBy.

supportsValueLookup: boolean

Whether POST /v2/reports/filter-values can list this attribute’s values.

valueType: "string" | "number" | "boolean" | 3 more
One of the following:
"string"
"number"
"boolean"
"date"
"enum"
"id"
multiValue?: boolean
staticOptions?: Array<ReportAttributeOption { label, value } >

Fixed value set for enum-like attributes. Attributes without static options resolve values via POST /v2/reports/filter-values.

label: string
value: string
description: string
metrics: Array<ReportMetric { id, allowedAggregations, description, 13 more } >
id: string

Metric ID — use as metric in query requests.

allowedAggregations: Array<"count" | "sum" | "avg" | 6 more>
One of the following:
"count"
"sum"
"avg"
"median"
"min"
"max"
"range"
"percentile"
"value"
description: string
name: string
supportedFilterAttributeIds: Array<string>

Attribute IDs this specific metric accepts in filter expressions.

supportedGroupByDimensions: Array<string>

Attribute IDs this specific metric accepts as groupBy or segmentBy.

supportedViews: Array<"standard" | "hourly_heatmap" | "sankey">

Which view values POST /v2/reports/query accepts for this metric. Most metrics support standard and hourly_heatmap; conversation-flow metrics are sankey-only.

One of the following:
"standard"
"hourly_heatmap"
"sankey"
supportsOfficeHours: boolean
supportsPeriodComparison: boolean
type: "count" | "percentage" | "duration" | "number"
One of the following:
"count"
"percentage"
"duration"
"number"
unit: "count" | "percentage" | "duration_ms" | "number"
One of the following:
"count"
"percentage"
"duration_ms"
"number"
dataAvailableFromIso?: string

Local calendar date (ISO 8601) from which this specific metric has data, when it differs from the global reporting floor. Windows ending before this date are rejected for this metric.

isDefaultVariant?: boolean

Whether this variant is the default selection for its variantGroupId.

variantGroupId?: string

Metrics sharing a variantGroupId are timestamp variants of one logical metric (same display name); each measures the same population at a different timestamp. Query the concrete metric id to pick a variant.

variantId?: string

Stable identifier for this variant within its group (e.g. created_at, started_at).

variantLabel?: string

Human-readable variant label for pickers (e.g. Created at, Started at).

name: string
object: "list"
ReportQueryResponse { meta, object, value, 7 more }
meta: Meta { aggregation, datasetId, granularity, 5 more }
aggregation: "count" | "sum" | "avg" | 6 more

Aggregation function applied to the metric. Each metric supports a subset of aggregations — see the allowedAggregations field in the GET /v2/reports/datasets catalog.

One of the following:
"count"
"sum"
"avg"
"median"
"min"
"max"
"range"
"percentile"
"value"
datasetId: string
granularity: string
metric: string
officeHoursOnly: boolean
unit: "count" | "percentage" | "duration_ms" | "number"
One of the following:
"count"
"percentage"
"duration_ms"
"number"
groupBy?: string
segmentBy?: string
object: "report_query_result"
value: number

Aggregated value across the whole reporting window.

deltaPercent?: number

Percentage change vs the comparison window.

flowData?: Array<FlowData>
metricId: string
pathId: string
source: string
sourceLabel: string
target: string
targetLabel: string
value: number
colorKey?: string
percentage?: number
sortOrder?: number
groupedData?: Array<ReportGroupedDatum { group, value, groupLabel, 2 more } >
group: string

Raw group value (e.g. an ID). Use groupLabel for display.

value: number
groupLabel?: string
previousValue?: number
segments?: Array<ReportSegmentDatum { segment, value, previousValue, segmentLabel } >
segment: string
value: number
previousValue?: number
segmentLabel?: string
previousValue?: number

Aggregated value for the comparison window, when requested.

segmentData?: Array<ReportSegmentDatum { segment, value, previousValue, segmentLabel } >
segment: string
value: number
previousValue?: number
segmentLabel?: string
table?: Table { columns, key, mode, 6 more }
columns: Array<Column>
id: string
kind: "dimension" | "metric" | "record_attribute"
One of the following:
"dimension"
"metric"
"record_attribute"
label: string
sortable: boolean
unit: "count" | "percentage" | "duration_ms" | 3 more
One of the following:
"count"
"percentage"
"duration_ms"
"number"
"text"
"datetime"
align?: "left" | "right"
One of the following:
"left"
"right"
sticky?: boolean
summary?: "sum" | "weighted_rate" | "none"
One of the following:
"sum"
"weighted_rate"
"none"
valueType?: string
key: string
mode: "aggregate" | "records"
One of the following:
"aggregate"
"records"
page: number
pageSize: number
rows: Array<Row>
id: string
cells: Record<string, Cells>
display: string
denominator?: number
numerator?: number
raw?: unknown
sortValue?: string | number | null
One of the following:
string
number
value?: unknown
totalRows: number
sort?: Sort { columnId, direction }
columnId: string
direction: "asc" | "desc"
One of the following:
"asc"
"desc"
summaryRows?: Array<SummaryRow>
id: string
cells: Record<string, Cells>
display: string
denominator?: number
numerator?: number
raw?: unknown
sortValue?: string | number | null
One of the following:
string
number
value?: unknown
timeSeries?: Array<ReportTimeSeriesDatum { date, value, previousValue, segments } >
date: string

Time bucket start (ISO 8601).

value: number
previousValue?: number

Value for the same bucket in the comparison window, when requested.

segments?: Array<ReportSegmentDatum { segment, value, previousValue, segmentLabel } >
segment: string
value: number
previousValue?: number
segmentLabel?: string
ReportLookupFilterValuesResponse { data, object }
data: Array<ReportAttributeOption { label, value } >
label: string
value: string
object: "list"
ReportDrillInResponse { availableColumns, defaultColumnIds, meta, 6 more }
availableColumns: Array<AvailableColumn>
id: string

Column ID (an attribute ID or metric.value).

name: string
supportsSort: boolean

Whether this column may be used in the drill-in sort request.

valueType: string
category?: string
defaultColumnIds: Array<string>
meta: Meta { datasetId, metricId, rawMetricId, 6 more }
datasetId: string
metricId: string
rawMetricId: string
reconciliation: Reconciliation { kind, rowCount, status, 4 more }
kind: "rows" | "actions_across_conversations" | "active_hour_rate" | 2 more
One of the following:
"rows"
"actions_across_conversations"
"active_hour_rate"
"positive_ratings_over_eligible_ratings"
"missed_over_evaluated"
rowCount: number
status: "not_applicable" | "available" | "denominator_unavailable"
One of the following:
"not_applicable"
"available"
"denominator_unavailable"
denominatorHours?: number
displayedRate?: number
eligibleDenominatorTotal?: number
rawNumeratorTotal?: number
rowGrain: string
rowSemantics: "metric_rows" | "numerator_rows"
One of the following:
"metric_rows"
"numerator_rows"
sourceFact: string
emptyReason?: "no_matching_rows" | "denominator_unavailable"
One of the following:
"no_matching_rows"
"denominator_unavailable"
metricRowId?: string
object: "report_drill_in_result"
page: number
pageSize: number
rows: Array<Record<string, string | number | boolean | 3 more | null>>

One record per underlying row, keyed by column ID.

One of the following:
string
number
boolean
Array<string>
ReportDrillInIdentityCell { id, kind, label, 3 more }
id: string
kind: "identity"
label: string
avatarUrl?: string
color?: string
provenance?: "current" | "historical" | "fallback" | "unassigned"
One of the following:
"current"
"historical"
"fallback"
"unassigned"
ReportDrillInSourceDetailsCell { items, kind }
items: Array<Item>
label: string
id?: string
type?: string
url?: string
formaturi
kind: "source_details"
timezone: string
total: number