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

# Metrics

> Discover metric names and dimensions, then evaluate PromQL instant and range queries

Metrics are queried with **PromQL**. Always discover first — `/v1/metrics` supplies the exact names, kinds, units, and label dimensions to copy into queries. Don't guess names.

## `GET /v1/metrics` — the catalogue

Lists metrics observed over the last 24 hours by default. Pass `since`/`until` to widen discovery up to a 30-day span — useful for finding a metric that stopped emitting days ago — and trust the echoed `range_start`/`range_end`.

```json theme={null}
{
  "project_id": "prj_...",
  "range_start": "...",
  "range_end": "...",
  "metrics": {
    "items": [
      {
        "name": "paymentramp.sessions.active",
        "kind": "gauge",
        "unit": "{session}",
        "dimensions": { "items": [ { "key": "service.name", "values": { "items": [...], "truncated": false } } ], "truncated": false }
      }
    ],
    "truncated": false
  }
}
```

Truncation semantics: a missing metric is conclusive only when `metrics.truncated: false`; a missing dimension only when that metric's `dimensions.truncated: false`; dimension values are exhaustive only when `values.truncated: false`. The 200-metric cap is **alphabetical**, so a wider window can push a busy project past it and drop later-named metrics.

## Pick the query idiom from `kind`

| Kind                                 | Meaning               | Typical PromQL                                                                                       |
| ------------------------------------ | --------------------- | ---------------------------------------------------------------------------------------------------- |
| `gauge`                              | Point-in-time value   | `avg by ("service.name") ({__name__="paymentramp.sessions.active"})`                                 |
| `sum`                                | Monotonic counter     | `sum by ("service.name") (rate({__name__="paymentramp.order.probe.success"}[5m]))`                   |
| `histogram`, `exponential_histogram` | Bucketed distribution | `histogram_quantile(0.99, sum by (le) (rate({__name__="http.server.request.duration_bucket"}[5m])))` |

* The catalogue lists a histogram's **base name only** — append `_bucket`, `_count`, or `_sum` inside the `__name__` matcher. `histogram_avg`, `histogram_count`, and `histogram_sum` are also available.
* Summaries never appear in the catalogue.
* `kind` cannot distinguish delta-temporality sums from cumulative ones. Querying a delta series returns `400` `VALIDATION_ERROR` (`delta-temporality is not supported here`) — that's **terminal for the series**; don't rewrite the expression and retry.

## Dotted names need `__name__` selectors

Names are stored exactly as emitted, and real Mirador names are dotted (`mirador.derived.client_slippage_bps`) — which makes them invalid as bare PromQL identifiers. Write:

* Dotted metric: `{__name__="http.server.request.duration"}`
* Dotted label matcher: `{"http.route"="/pay"}`
* Dotted grouping key: `sum by ("http.route") (...)`

Copy exact names from the catalogue. `__name__` matching must be exact — regex metric-name selection is rejected.

## `GET /v1/metrics/query` — instant

Evaluates PromQL at one instant. **`query` is required**; `time` defaults to now.

```bash theme={null}
curl -sS --fail-with-body -G \
  -H "Authorization: Bearer $MIRADOR_SERVER_KEY" \
  --data-urlencode 'query=avg by ("service.name") ({__name__="paymentramp.sessions.active"})' \
  https://api.mirador.org/v1/metrics/query
```

## `GET /v1/metrics/query_range` — range

Evaluates PromQL across a range. **`query` and `step` are both required** — omitting `step` is a `400`. `end` defaults to now, `start` to one hour before `end`; both accept RFC 3339 or relative ages.

```bash theme={null}
curl -sS --fail-with-body -G \
  -H "Authorization: Bearer $MIRADOR_SERVER_KEY" \
  --data-urlencode 'query=avg by ("service.name") ({__name__="paymentramp.sessions.active"})' \
  --data-urlencode 'start=1h' \
  --data-urlencode 'step=5m' \
  https://api.mirador.org/v1/metrics/query_range
```

Range queries follow Prometheus semantics and include both `start` and `end` when they land on the step — a one-hour range at `5m` can contain 13 points. Ranges are point-count limited: on `QUERY_TOO_BROAD`, widen `step` or shorten the range.

## Response envelope

A successful query is the familiar Prometheus shape:

```json theme={null}
{ "status": "success", "data": { "resultType": "vector", "result": [ { "metric": {...}, "value": [1755500000, "42"] } ] } }
```

* `vector`: `[{metric, value: [unix_seconds, "value"]}]`
* `matrix`: `[{metric, values: [[unix_seconds, "value"], ...]}]`
* `scalar` / `string`: `[unix_seconds, "value"]`

Timestamps are Unix seconds and **values are strings** so `NaN`, `+Inf`, and `-Inf` survive JSON — parse accordingly. An optional top-level `warnings` array carries non-fatal evaluation notes; surface the text verbatim and treat the result as a success.

<Note>
  A malformed or unsupported query is a `400` `VALIDATION_ERROR`, not an empty
  result — and API errors use Mirador's [typed envelope](/api/endpoints#errors),
  not Prometheus's. A successful **empty** `result` means the query ran and
  matched nothing.
</Note>

## Next Steps

<CardGroup cols={2}>
  <Card title="Dashboards" icon="table-columns" href="/api/dashboards">
    The same PromQL powers dashboard widgets
  </Card>

  <Card title="Metric alerts" icon="bell" href="/api/alerts">
    Fire notifications when a PromQL threshold crosses
  </Card>
</CardGroup>
