> ## Documentation Index
> Fetch the complete documentation index at: https://docs.armin.cx/llms.txt
> Use this file to discover all available pages before exploring further.

# Reports and metrics

> Discover support metrics and query report data with the Public API v1.

Use the Chatarmin CX reporting API to track ticket volume, response times, satisfaction, and automation in your own dashboards.

## Access and limits

Both endpoints extend the existing `/public/v1` API. Send your API key in the `cx-api-key` header. The key needs `analytics:read` and must be assigned to a support agent. Configure it in [Settings → API](https://armin.cx/app/_/settings/api).

Report queries enforce that agent's dashboard permissions and channel, team, and agent restrictions. A metric appearing in the catalog does not grant permission to read its data.

| Endpoint                         | Purpose                     | Rate tier                     |
| -------------------------------- | --------------------------- | ----------------------------- |
| `GET /public/v1/reports/metrics` | Discover metric definitions | List: 60 requests/minute      |
| `POST /public/v1/reports/query`  | Read report results         | Analytics: 10 requests/minute |

Neither endpoint changes tickets or sends messages. See [rate limits](/api/rate-limits) for retry guidance and the [OpenAPI reference](https://api.armin.cx/docs/v1) for complete response schemas.

## Discover metrics

```bash theme={null}
curl 'https://api.armin.cx/public/v1/reports/metrics' \
  -H "cx-api-key: $CX_API_KEY"
```

The response is `{ "success": true, "data": [...] }`. It contains the complete static catalog, without pagination. Each entry has:

| Field                  | Meaning                                                                        |
| ---------------------- | ------------------------------------------------------------------------------ |
| `id`                   | Metric identifier for `SHOW` and `VISUALIZE`, such as `new_tickets`            |
| `label`, `description` | Display name and definition                                                    |
| `group`, `dataType`    | Metric category and value type                                                 |
| `format`               | `count`, `duration-seconds`, `percent`, `decimal`, or `currency-eur`           |
| `aggregation`          | `count`, `sum`, `median`, `average`, or `ratio`                                |
| `attribution`          | Which event or snapshot determines the metric's period                         |
| `denominator`          | Optional explanation of the denominator or calculation                         |
| `snapshot`             | Whether the metric describes the current state rather than historical activity |
| `higherIsBetter`       | Whether an increase represents an improvement                                  |

The catalog contains no ticket records, customer information, workspace entity IDs, or internal data-source names. Labels and descriptions are in English. Cache this metadata rather than fetching it before every query. Not every metric supports every grouping or visualization.

## Query report data

Start with one metric and a short period. Send JSON with exactly two fields: `query` and an IANA `timezone`, such as `Europe/Vienna` or `UTC`.

```bash theme={null}
curl 'https://api.armin.cx/public/v1/reports/query' \
  -H "cx-api-key: $CX_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"query":"FROM tickets\nSHOW new_tickets\nDURING yesterday\nVISUALIZE new_tickets TYPE kpi","timezone":"Europe/Vienna"}'
```

The response uses `{ "success": true, "data": ... }`. Inspect `data.kind` to interpret the result: for example, `kpi` contains `value`, `previousValue`, and `format`; `time-series` contains `series` and `points`. The request returns chart data, not an image or CSV export.

### Query language

Write each clause on its own line. This is the CX report query language, not SQL: there are no arbitrary tables, joins, or SQL expressions.

| Clause                                  | Usage                                                                                                                                                     |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FROM tickets`                          | Required. Only the `tickets` dataset is supported.                                                                                                        |
| `SHOW new_tickets, resolved_tickets`    | Required. Use IDs from the metric catalog.                                                                                                                |
| `DURING yesterday`                      | Required date range, or use `SINCE ... UNTIL ...` instead. Other named periods include `today`, `this_week`, `last_week`, `this_month`, and `last_month`. |
| `SINCE 2026-08-01 UNTIL 2026-08-07`     | Explicit calendar dates in the supplied timezone. Includes the end date. Do not combine with `DURING`.                                                    |
| `WHERE status is_one_of open, resolved` | Optional filter. Repeat `WHERE` on separate lines to require multiple conditions.                                                                         |
| `GROUP BY channel`                      | Optional category grouping.                                                                                                                               |
| `TIMESERIES day`                        | Optional time grouping: `hour`, `day`, `week`, or `month`.                                                                                                |
| `COMPARE TO previous_period`            | Optional comparison for KPI and supported time-series reports; also accepts `previous_year`.                                                              |
| `ORDER BY new_tickets DESC`             | Optional result ordering; use `ASC` or `DESC`.                                                                                                            |
| `LIMIT 25`                              | Optional result limit, up to 1,000.                                                                                                                       |
| `OPTIONS {"showAverageRow":true}`       | Optional allow-listed visualization options, for example on a data table.                                                                                 |
| `VISUALIZE new_tickets TYPE kpi`        | Required. Select metrics from `SHOW` and a supported visualization. Use one metric for a KPI.                                                             |

Common visualizations include `kpi`, `line`, `area`, `grouped_bar`, `stacked_bar`, `horizontal_bar`, and `data_table`. Charts require metrics with the same `format`. A `data_table` can mix formats and requires exactly one breakdown dimension. All metrics, including automation and CSAT, use `FROM tickets`; there are no separate message or survey datasets.

## Query examples

Send each complete query below as the `query` string in the HTTP request above, with `timezone: "Europe/Vienna"`. Dates and metric IDs stay in the same format in every example.

### Daily ticket volume

Compare tickets created and tickets resolved on each day. These are different event populations, not necessarily the same tickets.

```text theme={null}
FROM tickets
SHOW new_tickets, resolved_tickets
TIMESERIES day
SINCE 2026-08-01 UNTIL 2026-08-07
VISUALIZE new_tickets, resolved_tickets TYPE line
```

### Yesterday's ticket KPI

Compare new demand with the preceding day.

```text theme={null}
FROM tickets
SHOW new_tickets
DURING yesterday
COMPARE TO previous_period
VISUALIZE new_tickets TYPE kpi
```

### New tickets by channel

Rank channels by incoming ticket volume. Channel keys in results identify your workspace's channels, not a universal list of channel names.

```text theme={null}
FROM tickets
SHOW new_tickets
GROUP BY channel
DURING last_week
ORDER BY new_tickets DESC
LIMIT 10
VISUALIZE new_tickets TYPE horizontal_bar
```

### First response durations

Compare median waits for a qualifying human or AI reply with waits for a human reply. Both series return seconds; they are not averages.

```text theme={null}
FROM tickets
SHOW customer_first_response_time, human_first_response_time
TIMESERIES day
DURING last_week
VISUALIZE customer_first_response_time, human_first_response_time TYPE line
```

### CSAT score and sample size

Keep the score next to the number of responses so you can judge small samples. A table allows the decimal score and count in one result.

```text theme={null}
FROM tickets
SHOW csat_average, csat_responses, low_csat_tickets
GROUP BY day
DURING last_month
ORDER BY label ASC
VISUALIZE csat_average, csat_responses, low_csat_tickets TYPE data_table
```

### Automation savings and spend

Compare estimated savings with estimated spend in EUR. This is a same-format daily chart, not a billing reconciliation. These specialized automation metrics support KPIs, daily charts or tables, and action breakdowns except for AI spend. Do not mix them with unrelated ticket metrics or add category splits.

```text theme={null}
FROM tickets
SHOW money_saved, ai_spend
TIMESERIES day
DURING last_week
VISUALIZE money_saved, ai_spend TYPE line
```

### Filtered team workload

Review resolved German-language tickets by team, including resolution duration. Repeated filters are combined with AND. `status` is the current ticket status, not its status at the time of creation. For filters such as `team`, `channel`, or `human_agent`, use your workspace's entity IDs rather than display names.

```text theme={null}
FROM tickets
SHOW resolved_tickets, full_resolution_time
WHERE language is de
WHERE status is resolved
GROUP BY team
DURING last_week
ORDER BY resolved_tickets DESC
LIMIT 25
OPTIONS {"showAverageRow":false}
VISUALIZE resolved_tickets, full_resolution_time TYPE data_table
```

### Current customer-waiting snapshot

Count open tickets waiting for information from the customer, not customers waiting for support. The date clause is required by the language but does not turn a snapshot into historical data. Do not add `TIMESERIES` or `COMPARE TO` to snapshots.

```text theme={null}
FROM tickets
SHOW awaiting_response_now
DURING today
VISUALIZE awaiting_response_now TYPE kpi
```

## Read results

These are illustrative response shapes with invented values, not guaranteed results for the example periods. Rows and points are shortened. Use returned labels and keys rather than assuming translated labels or fixed channel IDs.

A KPI returns a number and its format. `previousValue` can be `null`; historical KPIs may already include a prior-period value without an explicit comparison. An explicit `COMPARE TO` selects the comparison period. Snapshot KPIs have no historical comparison.

```json theme={null}
{
  "success": true,
  "data": { "kind": "kpi", "value": 42, "previousValue": 38, "format": "count" }
}
```

Time-series point values use keys from `series`. Explicit comparisons add series keys ending in `__compare`.

```json theme={null}
{
  "success": true,
  "data": {
    "kind": "time-series",
    "format": "count",
    "series": [
      { "key": "new_tickets", "label": "New tickets" },
      { "key": "resolved_tickets", "label": "Resolved" }
    ],
    "points": [
      { "date": "2026-08-01", "label": "Aug 1", "values": { "new_tickets": 42, "resolved_tickets": 35 } }
    ]
  }
}
```

A category result contains labeled values.

```json theme={null}
{
  "success": true,
  "data": {
    "kind": "category",
    "format": "count",
    "items": [{ "key": "channel_example", "label": "Support email", "value": 42 }]
  }
}
```

A table describes each column's metric and format. Do not add or average daily percentages, medians, or averages to reconstruct a period KPI; query the KPI for that period instead.

```json theme={null}
{
  "success": true,
  "data": {
    "kind": "data_table",
    "rowDimension": "day",
    "columns": [
      { "measureId": "csat_average", "label": "CSAT", "format": "decimal" },
      { "measureId": "csat_responses", "label": "CSAT responses", "format": "count" },
      { "measureId": "low_csat_tickets", "label": "Low-CSAT tickets", "format": "count" }
    ],
    "rows": [
      { "key": "2026-08-01", "label": "Aug 1", "values": { "csat_average": 4.5, "csat_responses": 10, "low_csat_tickets": 1 } }
    ]
  }
}
```

## Metric reference

All 50 registered metric IDs are listed below, grouped as in the discovery catalog. Aggregation, format, and attribution are the exact catalog values. You select the metric, not a custom aggregation function.

* `count` counts the defined tickets, messages, surveys, actions, or events; `sum` adds values; `average` is an arithmetic mean; `median` is the middle observation; `ratio` divides the eligible numerator by its denominator.
* `duration-seconds` returns seconds, `currency-eur` returns EUR, `decimal` returns a decimal value, and `percent` returns percentage points: `75` means 75%, not `0.75`. CSAT scores use a 1-5 scale.
* Attribution chooses the date population: `ticket_created` is a creation cohort; `ticket_resolved`, `reply_event`, `reopen_event`, `reassignment_event`, `survey_submitted`, `action_executed`, and `order_paid` refer to their respective events. `agent_presence` measures online-session time; `mixed_events` combines creation and resolution; `current_snapshot` means now.
* Creation-cohort facts can change as tickets develop. In particular, `messages` and `messages_per_ticket` include recorded messages on tickets created in the period, not only messages sent during it. Use `agent_messages` for human public messages sent in the period.
* Current snapshots cannot use time dimensions or historical comparisons. Backlog age is measured from creation, not from the last message. Even with an older date clause, a snapshot is not an end-of-period backlog reconstruction.
* Rates use the denominators in their definitions below, within the applicable scope. A zero or empty result alone does not establish that no activity occurred: reporting data can be incomplete or awaiting updates. Validate important totals before using them for commitments or financial reporting.
* `csat_response_rate` is a sent-survey cohort: scored submissions divided by surveys sent in the period. Its catalog attribution is `survey_submitted`, but this calculation uses the sent date, unlike the other CSAT metrics.
* `time_saved` and `money_saved` are estimates based on your workspace's action-time and hourly-rate assumptions. `ai_spend` converts recorded AI credits using a fallback EUR-per-credit rate; it is not your invoice or a guarantee of your contracted price. Although its catalog attribution is `action_executed`, spend is dated by AI run creation, including spend on days without tracked actions.

### Volume and workload

| Metric ID               | Definition and denominator                                                                                                         | Aggregation | Format             | Attribution          |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------------ | -------------------- |
| `new_tickets`           | Tickets created in the period.                                                                                                     | `count`     | `count`            | `ticket_created`     |
| `resolved_tickets`      | Tickets resolved in the period.                                                                                                    | `count`     | `count`            | `ticket_resolved`    |
| `tickets_replied_to`    | Distinct tickets receiving a tracked public support reply in the period.                                                           | `count`     | `count`            | `reply_event`        |
| `answered_tickets`      | Distinct tickets with a human or AI message attributed to an agent in the period.                                                  | `count`     | `count`            | `reply_event`        |
| `reopened_tickets`      | Distinct tickets reopened in the period, not the number of reopen events.                                                          | `count`     | `count`            | `reopen_event`       |
| `backlog_now`           | Open, unresolved tickets now.                                                                                                      | `count`     | `count`            | `current_snapshot`   |
| `backlog_over_24h`      | Open tickets created more than 24 hours ago.                                                                                       | `count`     | `count`            | `current_snapshot`   |
| `backlog_over_48h`      | Open tickets created more than 48 hours ago.                                                                                       | `count`     | `count`            | `current_snapshot`   |
| `awaiting_response_now` | Open tickets waiting for information from the customer, not waiting for support.                                                   | `count`     | `count`            | `current_snapshot`   |
| `net_backlog_change`    | New tickets minus resolved tickets in the period; not a reconstruction of every backlog transition.                                | `sum`       | `count`            | `mixed_events`       |
| `messages`              | Total customer, human, and AI messages on tickets created in the period.                                                           | `sum`       | `count`            | `ticket_created`     |
| `agent_messages`        | Public business messages sent by human agents in the period.                                                                       | `count`     | `count`            | `reply_event`        |
| `messages_per_ticket`   | Customer, human, and AI messages divided by tickets created in the period.                                                         | `average`   | `decimal`          | `ticket_created`     |
| `agent_online_time`     | Total agent online time in the inbox during the period; not ticket handling time.                                                  | `sum`       | `duration-seconds` | `agent_presence`     |
| `one_touch_tickets`     | Resolved tickets with exactly one public support reply and no reopen.                                                              | `count`     | `count`            | `ticket_resolved`    |
| `one_touch_rate`        | One-touch tickets divided by resolved tickets.                                                                                     | `ratio`     | `percent`          | `ticket_resolved`    |
| `zero_touch_tickets`    | Resolved tickets with no human reply; does not mean no AI or automation activity.                                                  | `count`     | `count`            | `ticket_resolved`    |
| `reassignments`         | Assignment-change events in the period; a ticket can contribute more than once.                                                    | `count`     | `count`            | `reassignment_event` |
| `reassignment_rate`     | Reassigned tickets divided by tickets created in the period.                                                                       | `ratio`     | `percent`          | `ticket_created`     |
| `demand_coverage`       | Created tickets that reached final resolution divided by new tickets in the period, not resolved throughput divided by new demand. | `ratio`     | `percent`          | `ticket_created`     |
| `support_revenue`       | Shopify order revenue attributed to support tickets, in EUR, by order paid date.                                                   | `sum`       | `currency-eur`     | `order_paid`         |

### Response and resolution

| Metric ID                      | Definition and denominator                                                                                                                                        | Aggregation | Format             | Attribution       |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------------ | ----------------- |
| `customer_first_response_time` | Median wait for the first qualifying human or AI reply.                                                                                                           | `median`    | `duration-seconds` | `reply_event`     |
| `human_first_response_time`    | Median wait for the first qualifying human reply.                                                                                                                 | `median`    | `duration-seconds` | `reply_event`     |
| `ai_first_response_time`       | Median wait for the first qualifying AI reply.                                                                                                                    | `median`    | `duration-seconds` | `reply_event`     |
| `full_resolution_time`         | Median wall-clock time from ticket creation to resolution.                                                                                                        | `median`    | `duration-seconds` | `ticket_resolved` |
| `active_resolution_time`       | Median business-hours time from creation to resolution, minus customer-waiting periods.                                                                           | `median`    | `duration-seconds` | `ticket_resolved` |
| `waiting_on_customer_time`     | Median total customer-waiting time per resolved ticket, within business hours. Each ticket's total sums its human-support-reply to next-customer-reply intervals. | `median`    | `duration-seconds` | `ticket_resolved` |
| `sla_resolution_met`           | Resolution SLA deadlines met on time for tickets created in the period.                                                                                           | `count`     | `count`            | `ticket_created`  |
| `sla_resolution_breached`      | Resolution SLA deadlines breached for tickets created in the period.                                                                                              | `count`     | `count`            | `ticket_created`  |

### Quality and satisfaction

| Metric ID            | Definition and denominator                                                                                   | Aggregation | Format    | Attribution        |
| -------------------- | ------------------------------------------------------------------------------------------------------------ | ----------- | --------- | ------------------ |
| `reopen_rate`        | Resolved tickets with a reopen divided by resolved tickets.                                                  | `ratio`     | `percent` | `ticket_resolved`  |
| `csat_average`       | Average 1-5 score from scored surveys submitted in the period.                                               | `average`   | `decimal` | `survey_submitted` |
| `csat_responses`     | Scored surveys submitted in the period.                                                                      | `count`     | `count`   | `survey_submitted` |
| `csat_response_rate` | Surveys sent in the period that received a score divided by surveys sent; see the sent-date exception above. | `ratio`     | `percent` | `survey_submitted` |
| `low_csat_tickets`   | Distinct tickets with a submitted score of 3 or lower.                                                       | `count`     | `count`   | `survey_submitted` |

### AI and automation

| Metric ID                   | Definition and denominator                                                                          | Aggregation | Format             | Attribution        |
| --------------------------- | --------------------------------------------------------------------------------------------------- | ----------- | ------------------ | ------------------ |
| `ai_involved_tickets`       | Tickets created in the period where an AI agent ran or completed a tracked action.                  | `count`     | `count`            | `ticket_created`   |
| `ai_resolved_tickets`       | Tickets whose final outcome was resolved by an AI agent.                                            | `count`     | `count`            | `ticket_resolved`  |
| `ai_resolution_rate`        | AI-resolved tickets divided by AI-involved resolved tickets, not all incoming tickets.              | `ratio`     | `percent`          | `ticket_resolved`  |
| `human_handoffs`            | Resolved tickets with a recorded AI-to-human handoff, dated by resolution rather than handoff time. | `count`     | `count`            | `ticket_resolved`  |
| `handoff_rate`              | Human handoffs divided by AI-involved resolved tickets.                                             | `ratio`     | `percent`          | `ticket_resolved`  |
| `workflow_resolved_tickets` | Resolved tickets completed through workflow automation.                                             | `count`     | `count`            | `ticket_resolved`  |
| `workflow_resolution_rate`  | Workflow-resolved tickets divided by resolved tickets.                                              | `ratio`     | `percent`          | `ticket_resolved`  |
| `ai_actions`                | Tracked customer-facing actions completed by AI in the period.                                      | `count`     | `count`            | `action_executed`  |
| `human_actions`             | Tracked customer-facing actions completed by humans in the period.                                  | `count`     | `count`            | `action_executed`  |
| `action_automation_rate`    | AI actions divided by total tracked actions; not an average of per-ticket automation percentages.   | `ratio`     | `percent`          | `action_executed`  |
| `time_saved`                | Estimated human time saved by AI actions using workspace action-time assumptions.                   | `sum`       | `duration-seconds` | `action_executed`  |
| `money_saved`               | Estimated EUR saved using time savings and the workspace hourly rate.                               | `sum`       | `currency-eur`     | `action_executed`  |
| `ai_spend`                  | Estimated EUR from recorded AI credits at the fallback rate; see the run-date exception above.      | `sum`       | `currency-eur`     | `action_executed`  |
| `ai_reopen_rate`            | AI-resolved tickets that reopened divided by AI-resolved tickets.                                   | `ratio`     | `percent`          | `ticket_resolved`  |
| `ai_csat`                   | Average submitted CSAT score for AI-involved tickets, on the 1-5 scale.                             | `average`   | `decimal`          | `survey_submitted` |
| `ai_suggestion_used_rate`   | AI draft suggestions used divided by AI suggestions offered, on tickets resolved in the period.     | `ratio`     | `percent`          | `ticket_resolved`  |

## Troubleshooting

| Response | What to check                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401`    | Supply a valid API key.                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `403`    | Grant `analytics:read`, assign the key to an agent, and check that agent's dashboard permissions for queries.                                                                                                                                                                                                                                                                                                                                                                             |
| `400`    | Check clause syntax, metric IDs, timezone, and metric/grouping compatibility. Keep ranges within 90 calendar days, or 31 days for hourly reports. Oversized ranges return `VALIDATION_ERROR` with `details.requested_days`, `details.max_days`, and `details.timezone`. Split the query into non-overlapping `SINCE`/`UNTIL` windows; both dates are inclusive, so start the next window on the following day. Reduce metrics or comparisons when the query exceeds its execution budget. |
| `429`    | Wait for the `Retry-After` header before retrying.                                                                                                                                                                                                                                                                                                                                                                                                                                        |

Date-range validation, an estimated query-cost check, and returned row/point limits do not guarantee a universal execution deadline or a cap on every result cell or underlying database operation. `LIMIT` trims returned rows or points; it is not pagination or a guarantee of less database work. Split large reporting jobs into smaller date windows. Historical completeness and freshness depend on the available reporting data; a successful response does not certify either. If a valid small query fails or totals look incomplete, contact support with the response `request_id`, timezone, and a redacted query. Never share your API key.
