# 3pm-backend route `metricsCatalog`

Paths are relative to the backend's origin (https://fleet.edgecr4ft.net, or your own 3pm-backend), not to this site. Index: https://3pm.edgecr4ft.net/docs/backend/api.md

---

tokens:
  claude: 1064
  o200k: 720
# GET /api/buckets/{clusterId}/metrics/catalog (metricsCatalog)

Every metric a query may name: id, kind, unit, labels, default time function.

- auth: an account — Authorization: Bearer 3pmu_<token>, or the dashboard's session cookie
- answer: MetricDef[] (JSON)

## Details

Every metric this bucket can be queried on, static and application alike: `{ id, kind, unit, labels, default_time, source, doc }`. `id` is what a query's `metric` names, `labels` what its `filters` and `aggregate.by` may use, `default_time` the time function applied when the query gives none, and `source` tells a built-in line (`static`) from one an application sent here (`app`, id prefixed `app.`). Read it before building a query: nothing else says which metrics exist on this bucket, and a query naming one it lacks is refused.

## Types

```ts
/** One line of `metricsCatalog`. */
interface MetricDef {
  id: string;
  kind: MetricKind;
  unit: string;
  /** What `filters` and `by` may name for this metric. */
  labels: QueryLabel[];
  /** What a chart wants when `time` is omitted. */
  default_time: TimeFn;
  description: string;
  source: MetricSource;
}

type MetricKind = "gauge" | "counter" | "histogram";

/** The labels a query may filter or group on; the bucket itself is never one of them. */
/** A built-in label, or an application's own label name (`^[a-z][a-z0-9_]{0,31}$`, not reserved) on a metric that carries it. */
type QueryLabel = "node" | "app" | "instance" | "ns" | "mount" | "window" | "src" | "core" | "iface" | "blockdev" | "sensor" | "gpu" | "array" | "proc" | (string & {});

interface TimeFn {
  fn: TimeFnName;
  /** `1m` or milliseconds, like `range.step`; default twice the step. Not for `raw`. */
  window?: DurationValue;
  /** 0..1, `quantile_over_time` and `quantile` (a histogram's) only. */
  q?: number;
}

/** Where a catalog line comes from: the store's own telemetry, or an application's metric seen in this bucket. */
type MetricSource = "static" | "app";

/** `rate`, `increase`, `delta` for counters; the `*_over_time` family for gauges; `raw` for either; `quantile` (with `q`), `rate` or `increase` for a histogram. */
type TimeFnName =
  | "raw"
  | "rate"
  | "increase"
  | "delta"
  | "avg_over_time"
  | "min_over_time"
  | "max_over_time"
  | "last_over_time"
  | "quantile_over_time"
  | "quantile";

/** Milliseconds, or `30s` / `5m` / `1h` / `7d` / `2w`. */
type DurationValue = number | string;
```
