# Metrics

## Metric Model

### Fields

- **`object`** `"metric"`

- **`id`** `string`

- **`name`** `string`

- **`team_id`** `string`

- **`project_id`** `string`

- **`deleted_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   When the metric is scheduled to be deleted; null when it is not.

- **`view_id`** `string`

   The view whose records the metric aggregates. Changing it to a compatible view in the same
   project rebuilds the metric's historical data.

- **`status`** [`MetricStatus`](/api/metrics#metric-status)

   Current lifecycle state for live collection and historical backfill.

- **`group_by`** `string[]`

   View fields whose value combinations define distinct metric series.

- **`filters`** `string`

   Filter expression applied to records before aggregation.

- **`timestamp_field`** `string`

   View field used as the aggregation timestamp.

- **`value_field`** `string | null`

   View field used as the numeric aggregation value.

- **`unique_field`** `string | null`

   View field used for distinct-value counts.

- **`null_handling`** [`NullHandling`](/api/metrics#null-handling)

   How null or missing metric values are aggregated.

- **`empty_bucket_handling`** [`EmptyBucketHandling`](/api/metrics#empty-bucket-handling)

   How chart buckets without observations are represented.

- **`group_by_display_fields`** `Record<string, string> | null`

   Display labels for the fields in `group_by`.

- **`backfill_strategy`** [`BackfillStrategy`](/api/metrics#backfill-strategy)

   Order used when historical data is rebuilt.

- **`ui_chart_family`** [`ChartFamily`](/api/metrics#chart-family)

   Read-only: derived from `ui_chart_type`, grouping chart types by layout family.

- **`ui_chart_type`** [`ChartType`](/api/metrics#chart-type)

- **`ui_chart_color_mode`** [`ChartColorMode`](/api/metrics#chart-color-mode)

   Strategy used to assign chart colors.

- **`ui_chart_color_base`** `string | null`

   Base color used by intensity mode, one of `CHART_COLORS`. Null when the color mode does not use
   one.

- **`ui_chart_color_rules`** `MetricColorRule[] | null`

   Ordered value-to-color rules used by value mode.

- **`ui_chart_curve`** [`ChartCurve`](/api/metrics#chart-curve)

   Line interpolation style.

- **`ui_chart_show_alerts`** `boolean`

   Whether the chart displays alert markers.

- **`ui_chart_compact_values`** `boolean`

   Whether chart tooltips round values to compact notation, such as 321.3M.

- **`ui_chart_y_min`** `number | null`

   Fixed lower bound for the y axis. Null lets the axis fit the data.

- **`ui_chart_y_max`** `number | null`

   Fixed upper bound for the y axis. Null lets the axis fit the data.

- **`ui_chart_show_monitors`** `boolean`

   Whether the chart displays monitor thresholds.

- **`ui_chart_show_trends`** `boolean`

   Whether the chart displays regression trends.

- **`ui_chart_show_forecast`** `boolean`

   Whether the chart opens with its forecast shown, projecting the fitted trend past now to the
   saved horizon. Viewers in the app can change the forecast for their own view without changing
   this setting.

- **`ui_chart_forecast_horizon`** [`ForecastHorizon`](/api/metrics#forecast-horizon)

   How far past now the chart projects when it draws a forecast. Relative values resolve against
   the moment the chart is viewed, not the moment they were saved.

- **`ui_chart_forecast_model`** [`ForecastModel`](/api/metrics#forecast-model)

   Curve the forecast is fitted with. `auto` follows whichever model fits the series best at view
   time, so the projected shape can change as data arrives.

- **`ui_value_unit`** `string | null`

   Unit label displayed with chart values.

- **`ui_chart_value`** [`MetricChartValue`](/api/metrics#metric-chart-value)

   Aggregation value displayed by default.

- **`ui_chart_time_range`** [`AnalyticsTimeRange`](/api/metrics#analytics-time-range)

   Window the chart covers by default.

- **`ui_chart_interval`** [`ChartInterval`](/api/metrics#chart-interval)

   Bucket size the chart uses by default.

- **`ui_chart_custom_range_start_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   Start of the custom chart range.

- **`ui_chart_custom_range_end_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   End of the custom chart range.

- **`ui_chart_max_series`** `number`

   Maximum number of individual series displayed by default.

- **`created_at`** [`ISODateString`](/api/metrics#iso-date-string)

- **`updated_at`** [`ISODateString`](/api/metrics#iso-date-string)

- **`backfill_percent`** `number`

   Percentage of the view's data files the historical backfill has processed.

- **`backfill_total_count`** `number`

   How many of the view's data files the historical backfill has to process. Seeded as 1 before
   the run is planned.

- **`backfill_completed_count`** `number`

   How many of those files it has processed.

- **`backfill_completed_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   Null until the backfill finishes.

- **`backfill_started_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   Null until the backfill starts.

- **`compact_percent`** `number`

   Percentage of rollup-building steps completed.

- **`compact_total_count`** `number`

   How many rollup-building steps the run has planned; 0 until that pass starts.

- **`compact_completed_count`** `number`

   How many of those steps are done.

- **`compact_started_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   Null until the rollup-building pass starts.

- **`has_triggered_monitors`** `boolean`

   Whether at least one alert is currently open. Ended alerts remain in history.

### Referenced Types

#### ISODateString

`ISODateString`

An ISO 8601 date-time string returned at the JSON API boundary.

#### MetricStatus

`"initializing" | "waiting_for_transforms" | "backfilling" | "active" | "error" | "cancelled"`

#### NullHandling

`"skip" | "count_as_zero"`

#### EmptyBucketHandling

`"zero" | "gaps"`

#### BackfillStrategy

`"newest_first" | "oldest_first"`

#### ChartFamily

`"cartesian" | "radial" | "geographic" | "temporal" | "hierarchical"`

#### ChartType

`"line" | "area" | "bar" | "pie" | "scatter" | "radar" | "stat" | "gauge" | "calendar" | "uptime"`

#### ChartColorMode

`"by_series" | "by_intensity" | "by_value"`

#### ChartColor

`"blue" | "red" | "amber" | "green" | "teal" | "purple" | "pink"`

#### ChartCurve

`"linear" | "step" | "smooth"`

#### ForecastHorizon

`"next_7_days" | "next_30_days" | "next_90_days" | "end_of_quarter" | "end_of_year" | "next_year"`

How far past now a chart projects its forecast. Values are relative to the moment the chart is
viewed, so a saved horizon keeps projecting the same distance ahead as time passes rather than
expiring on a fixed date. `end_of_quarter` and `end_of_year` run to the end of the calendar
period that contains today, in UTC.

#### ForecastModel

`"auto" | "linear" | "exponential" | "logarithmic" | "logistic" | "sinusoidal"`

The curve a forecast is fitted with. `auto` follows the best-fitting model for the series, which
is recalculated as data arrives and can therefore change between views; naming a model pins the
projection to that curve.

#### MetricChartValue

`"count" | "average" | "sum" | "min" | "max" | "last" | "cumulative_sum" | "cumulative_count" | "p50" | "p95" | "p99" | "count_unique"`

Aggregation applied to a metric's values. Use `last` when records are snapshots of a persistent
thing such as a deal, user, or inventory item: each time bucket contains the latest reading for
that series in the bucket. Within the requested range, the last observed value carries forward
across complete empty intervals instead of reading them as zero.

#### AnalyticsTimeRange

`"last_hour" | "last_6_hours" | "today" | "last_24_hours" | "yesterday" | "this_week" | "last_week" | "this_month" | "last_month" | "this_quarter" | "last_quarter" | "this_year" | "last_year" | "last_7_days" | "last_30_days" | "last_90_days" | "last_365_days" | "all_time" | "custom" | "next_7_days" | "next_30_days" | "next_90_days"`

The window a chart reads. Stored as a plain string rather than a database enum: the set is
presentation, not something any query filters on, and the forward ranges in particular are
expected to change as we learn what people forecast over.

A `next_*` range ends after now, which is what turns a fitted trend into a visible forecast. The
measured half of such a range is still measured; only the part past now is projected.

#### ChartInterval

`"minute" | "hour" | "day" | "month" | "auto"`

The Data Interval _setting_ (`Metric.ui_chart_interval` and the aggregation `interval` query
param). `"auto"` means the server picks the finest-safe tier for the current view, so brush-zoom
naturally drills into a finer bucket. The RESOLVED tier returned by aggregation is always a plain
`DataInterval`.

## Timeseries Aggregation Model

### Fields

- **`object`** `"aggregation"`

- **`coverage_mode`** `"strict" | "observed" | null`

   Null for telemetry endpoints without a metric completeness contract.

- **`coverage_reasons`** `{ view_id: string; view_name: string; reason: string; count: number | null; }[]`

   Count is null when the reason reports a status rather than a measured count.

- **`start_at`** [`ISODateString`](/api/metrics#iso-date-string)

- **`end_at`** [`ISODateString`](/api/metrics#iso-date-string)

- **`interval`** [`DataInterval`](/api/metrics#data-interval)

   Bucket size each entry in a series' `records` covers.

- **`values`** [`MetricChartValue[]`](/api/metrics#metric-chart-value)

   Declares what each number in a series' `records` arrays means; positions align.

- **`series`** [`MetricSeries[]`](/api/metrics#aggregation-series-model)

   One entry per charted series. An explicit series filter returns exactly those series; otherwise
   pinned series are kept and every other series folds into a synthetic `__other__` entry, and
   with no pins the top series by value are kept up to the chart's limit.

- **`series_total`** `number`

   Distinct real series permutations that had data in the requested range before the server folded
   the tail into the synthetic `__other__` series. Always present; equals the named series count
   when nothing folds. Clients subtract the number of named series they display to size the single
   "Other (N)" row and its warning, instead of counting the (already-folded) `series` array.

- **`complete_through_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   Everything before this instant is final. Later buckets may still be filling in while ingest,
   transforms, or backfills catch up, so treat them as provisional. Null when no statement can be
   made, which is not the same as complete.

### Referenced Types

#### ISODateString

`ISODateString`

An ISO 8601 date-time string returned at the JSON API boundary.

#### DataInterval

`"minute" | "hour" | "day" | "month"`

#### MetricChartValue

`"count" | "average" | "sum" | "min" | "max" | "last" | "cumulative_sum" | "cumulative_count" | "p50" | "p95" | "p99" | "count_unique"`

Aggregation applied to a metric's values. Use `last` when records are snapshots of a persistent
thing such as a deal, user, or inventory item: each time bucket contains the latest reading for
that series in the bucket. Within the requested range, the last observed value carries forward
across complete empty intervals instead of reading them as zero.

## Aggregation Series Model

### Fields

- **`details`** `{ label: string; hash: string; dimensions: Record<string, string | number | boolean | null>; color: string | null; }`

   The series' identity (`hash`, `dimensions`) and current presentation (`label`, `color`).

- **`records`** `Record<string, (number | null)[]>`

   One entry per bucket, values aligned with the aggregation's `values` list. `null` means the
   bucket had no data and the metric's `empty_bucket_handling` is `gaps`.

- **`regression`** `LinearRegression | ExponentialRegression | LogarithmicRegression | LogisticRegression | SinusoidalRegression | null`

   Trend line fitted over the series; null when none was computed.

- **`forecast`** `RegressionForecast | null`

   The trend line's projected next value; null when no trend was computed.

### Referenced Types

#### ISODateString

`ISODateString`

An ISO 8601 date-time string returned at the JSON API boundary.

## Metric Series Model

### Fields

- **`object`** `"metric_series"`

- **`id`** `string`

- **`metric_id`** `string`

- **`hash`** `string`

   Opaque identifier of the series' dimension combination, stable for the life of the metric.

- **`dimensions`** `Record<string, string | number | boolean | null>`

   The `group_by` field values that define this series.

- **`display_values`** `Record<string, string | null> | null`

   Readable value per dimension, read from the metric's `group_by_display_fields`; null when the
   metric defines none.

- **`display_label`** `string | null`

   Readable name for the series, auto-derived at discovery or set explicitly. When null, charts
   build a label from the raw `dimensions`.

- **`first_seen_at`** [`ISODateString`](/api/metrics#iso-date-string)

   When the series was registered. Stamped with the processing time, so a backfill registers
   historical combinations at run time.

- **`last_seen_at`** [`ISODateString`](/api/metrics#iso-date-string)

   Also stamped at registration; not a recency signal, use `last_value_at` for that.

- **`last_value`** `number | null`

   The most recent aggregated value observed for the series; used to rank series when none are
   pinned.

- **`last_value_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   When `last_value` was recorded.

- **`color`** `string | null`

   Chart color override; null means the color is picked automatically.

- **`pinned_at`** [`ISODateString | null`](/api/metrics#iso-date-string)

   When the series was pinned; null means not pinned. Pins replace ranking: charts keep the pinned
   series and fold every other series into `__other__`, unless an explicit series filter is sent.

### Referenced Types

#### ISODateString

`ISODateString`

An ISO 8601 date-time string returned at the JSON API boundary.

## List Metrics

### Endpoint

Retrieve a list of metrics for a project.

```http
GET /v1/projects/:project_id/metrics
```

**Scope:** `metrics:read`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

### Query Parameters

- **`view_id`** `string`
  Return metrics that read from this view. Optional.

- **`order_by`** `string`
  Field used to order the metrics. Optional. Defaults to `"name"`. Allowed values: `"name"`.

- **`deleted_at`** [`NullableDateFilter`](/api/metrics#nullable-date-filter)
  Filter on deletion state. Pass `null` for metrics that are not scheduled for deletion. Optional.

- **`limit`** `number`
  Optional. Defaults to `25`. Minimum: `1`. Maximum: `200`.

- **`after`** `string`
  Cursor from `pagination.next_cursor` of a previous response. Returns the resources after that page. Optional.

- **`before`** `string`
  Cursor from `pagination.prev_cursor` of a previous response. Returns the resources before that page. Optional.

- **`sort`** `string`
  Optional. Defaults to `"asc"`. Allowed values: `"asc"`, `"desc"`.

### Response

```ts
{
  message: string;
  data: Metric[];
  status: 200;
  error: null;
  pagination: Pagination;
  endpoint: string;
}
```

### Comments

- `after` and `before` are mutually exclusive.

## Retrieve Metric

### Endpoint

Retrieve a single metric.

```http
GET /v1/projects/:project_id/metrics/:metric_id
```

**Scope:** `metrics:read`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

### Response

Metric retrieved

```ts
{
  message: string;
  data: Metric;
  status: 200;
  error: null;
  pagination: null;
  endpoint: string;
}
```

## Retrieve Metric Aggregation

### Endpoint

Retrieve aggregated time-series data for a metric.

```http
GET /v1/projects/:project_id/metrics/:metric_id/aggregation
```

**Scope:** `metrics:read`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

### Query Parameters

- **`coverage_mode`** `string`
  Strict returns only final data. Observed includes partial data beyond complete_through_at without filling missing buckets. Optional. Defaults to `"strict"`. Allowed values: `"strict"`, `"observed"`.

- **`start_at`** [`ISODateString`](/api/metrics#iso-date-string)
  Start of the aggregation range. Send together with `end_at`. Optional.

- **`end_at`** [`ISODateString`](/api/metrics#iso-date-string)
  End of the aggregation range. Send together with `start_at`. Optional.

- **`interval`** [`ChartInterval`](/api/metrics#chart-interval)
  Requested aggregation bucket interval. Optional.

- **`time_range`** [`AnalyticsTimeRange`](/api/metrics#analytics-time-range)
  Preset used to calculate the aggregation range. Ignored when `start_at` and `end_at` are both sent. Defaults to the metric's saved chart range. Optional.

- **`timezone`** `string`
  IANA timezone used to calculate date boundaries. Optional.

- **`page_id`** `string`
  Page whose saved custom range should be used. Applies only when `time_range` is `custom`. Optional.

- **`normalize`** `boolean`
  Whether the response includes empty time buckets. Optional. Defaults to `true`.

- **`forecast_at`** [`ISODateString`](/api/metrics#iso-date-string)
  Future timestamp requested for a forecast. Optional.

- **`max_series`** `integer`
  Maximum number of individual series to return. Optional. Minimum: `1`. Maximum: `50`.

- **`series`** `string`
  Comma-separated series hashes to return. Optional.

### Response

```ts
{
  message: string;
  data: TimeseriesAggregation;
  status: 200;
  error: null;
  pagination: null;
  endpoint: string;
}
```

### Comments

- `last` returns the latest reading in each time bucket within the requested range.
- `coverage_mode=observed` returns partial observed rows beyond the strict boundary without filling missing buckets. `coverage_reasons` names unresolved view scopes; `excluded` is informational.
- Record keys are UTC bucket starts. A bucket is final only when its UTC calendar end (start plus one `interval`) is at or before `complete_through_at`; strict omits all other buckets. A null cutoff means unknown completeness. Observed may include populated partial buckets even when the requested end lies inside one, and does not synthesize empty partial buckets.
- The aggregation window is resolved in order: an explicit `start_at` plus `end_at` wins; otherwise `time_range` is used; otherwise the metric's saved chart range is used.
- `start_at` and `end_at` only take effect when sent together. Sending one without the other has no effect on the window.
- When both are provided, `start_at` must be earlier than `end_at`.
- `time_range=custom` without explicit dates falls back to the saved custom range of `page_id`, then the metric, then the project.
- `timezone` must be a valid IANA timezone name, or `UTC`.

## Create Metric

### Endpoint

Create a metric for a project.

```http
POST /v1/projects/:project_id/metrics
```

**Scope:** `metrics:write`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

### Request Body

- **`name`** `string` -- **Required**
  The subject only, without the aggregation. Charts title themselves as the aggregation followed by this name, so `API Latency` renders as `P95 of API Latency`. Putting the aggregation here produces `P95 of API P95 Latency`. Minimum length: `1`. Maximum length: `64`.

- **`view_id`** `string` -- **Required**
  View that provides the metric's records. Maximum length: `32`.

- **`group_by`** `string[]`
  View fields used to split records into series. Optional. Defaults to `[]`.

- **`group_by_display_fields`** `object | null`
  Maps a field in `group_by` to another view field whose value labels the series, so a chart grouped on an opaque id reads as `api.example.com` instead of `chk_a1b2c3`. Each label is read from the first record of a series and kept from then on. Optional.

- **`filters`** `string`
  A query string of `?field=operator:value` pairs joined by `&`, applied when records are aggregated. For example `?status=equals:200` or `?level=in:error,warn&path=starts_with:/api`. Comma-separate the values of `in`, `not_in`, and `between`. Every operator must be spelled in full; short forms such as `eq:` are rejected. Optional. Defaults to `""`. Maximum length: `8192`.

- **`timestamp_field`** `string`
  View field used as the aggregation timestamp. Optional. Defaults to `"timestamp"`. Minimum length: `1`. Maximum length: `256`.

- **`value_field`** `string | null`
  View field used as the numeric aggregation value. Optional.

- **`unique_field`** `string | null`
  View field used to count distinct values. Optional.

- **`null_handling`** [`NullHandling`](/api/metrics#null-handling)
  How null or missing metric values are aggregated. Optional. Defaults to `"skip"`.

- **`empty_bucket_handling`** [`EmptyBucketHandling`](/api/metrics#empty-bucket-handling)
  How chart buckets without observations are represented. Optional.

- **`ui_chart_type`** [`ChartType`](/api/metrics#chart-type)
  Default chart type. Optional.

- **`ui_chart_color_mode`** [`ChartColorMode`](/api/metrics#chart-color-mode)
  Strategy used to assign chart colors. Optional.

- **`ui_chart_color_base`** [`ChartColor`](/api/metrics#chart-color)
  Base color used by intensity mode. Optional.

- **`ui_chart_color_rules`** `object[] | null`
  Ordered value-to-color rules used by value mode. Optional.

- **`ui_chart_show_alerts`** `boolean`
  Whether the chart displays alert markers. Optional.

- **`ui_chart_show_monitors`** `boolean`
  Whether the chart displays monitor thresholds. Optional.

- **`ui_chart_show_trends`** `boolean`
  Whether the chart displays regression trends. Optional.

- **`ui_chart_compact_values`** `boolean`
  Whether chart tooltips round values to compact notation, such as 321.3M instead of the full number. Optional.

- **`ui_chart_y_min`** `number | null`
  Fixed lower bound for the chart's y axis. Null lets the axis fit the data. Optional.

- **`ui_chart_y_max`** `number | null`
  Fixed upper bound for the chart's y axis. Null lets the axis fit the data. Optional.

- **`ui_chart_show_forecast`** `boolean`
  Whether the chart opens with its forecast shown, projecting the fitted trend past now to the saved horizon. Optional.

- **`ui_chart_forecast_horizon`** [`ForecastHorizon`](/api/metrics#forecast-horizon)
  How far past now the chart projects its forecast. The value is relative to when the chart is viewed, so it keeps projecting the same distance ahead as time passes. Optional.

- **`ui_chart_forecast_model`** [`ForecastModel`](/api/metrics#forecast-model)
  Curve the forecast is fitted with. Use `auto` to follow whichever model currently fits the series best. Optional.

- **`ui_value_unit`** `string`
  Unit label displayed with chart values. Optional. Maximum length: `32`.

- **`ui_chart_curve`** [`ChartCurve`](/api/metrics#chart-curve)
  Chart line interpolation style. Optional.

- **`ui_chart_value`** [`MetricChartValue`](/api/metrics#metric-chart-value)
  Aggregation value displayed by default. Optional.

- **`ui_chart_time_range`** [`AnalyticsTimeRange`](/api/metrics#analytics-time-range)
  Time range displayed by default. Optional.

- **`ui_chart_interval`** [`ChartInterval`](/api/metrics#chart-interval)
  Aggregation interval displayed by default. Optional.

- **`ui_chart_custom_range_start_at`** [`ISODateString`](/api/metrics#iso-date-string)
  Start of the custom chart range. Optional.

- **`ui_chart_custom_range_end_at`** [`ISODateString`](/api/metrics#iso-date-string)
  End of the custom chart range. Optional.

- **`ui_chart_max_series`** `integer`
  Maximum number of individual series displayed by default. Optional. Minimum: `1`. Maximum: `50`.

- **`backfill_strategy`** [`BackfillStrategy`](/api/metrics#backfill-strategy)
  Order used to rebuild historical data. Optional.

### Response

Your metric has been created and will begin collecting data immediately.

```ts
{
  message: string;
  data: Metric;
  status: 201;
  error: null;
  pagination: null;
  endpoint: string;
}
```

### Comments

- `view_id` is required when creating a metric.
- Field references and filters must be compatible with the selected view.
- Custom chart ranges require both dates, with an interval of at least 30 minutes.
- Color-mode configuration must match the selected chart color mode.
- `filters` must be a valid filter expression.
- `timestamp_field` cannot reference `__meta__` metadata.
- `group_by_display_fields` is set at create and cannot be changed afterwards, because each series takes its label from the first record it sees. Map a `group_by` field to a view field that carries a readable value for the same record.

## Update Metric

### Endpoint

Update an existing metric.

```http
POST /v1/projects/:project_id/metrics/:metric_id
```

**Scope:** `metrics:write`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

### Request Body

- **`name`** `string`
  The subject only, without the aggregation. Charts title themselves as the aggregation followed by this name, so `API Latency` renders as `P95 of API Latency`. Putting the aggregation here produces `P95 of API P95 Latency`. Optional. Minimum length: `1`. Maximum length: `64`.

- **`view_id`** `string`
  View that provides the metric's records. Optional. Maximum length: `32`.

- **`group_by`** `string[]`
  View fields used to split records into series. Optional.

- **`filters`** `string`
  A query string of `?field=operator:value` pairs joined by `&`, applied when records are aggregated. For example `?status=equals:200` or `?level=in:error,warn&path=starts_with:/api`. Comma-separate the values of `in`, `not_in`, and `between`. Every operator must be spelled in full; short forms such as `eq:` are rejected. Optional. Maximum length: `8192`.

- **`timestamp_field`** `string`
  View field used as the aggregation timestamp. Optional. Minimum length: `1`. Maximum length: `256`.

- **`value_field`** `string | null`
  View field used as the numeric aggregation value. Optional.

- **`unique_field`** `string | null`
  View field used to count distinct values. Optional.

- **`null_handling`** [`NullHandling`](/api/metrics#null-handling)
  How null or missing metric values are aggregated. Optional.

- **`empty_bucket_handling`** [`EmptyBucketHandling`](/api/metrics#empty-bucket-handling)
  How chart buckets without observations are represented. Optional.

- **`ui_chart_type`** [`ChartType`](/api/metrics#chart-type)
  Default chart type. Optional.

- **`ui_chart_color_mode`** [`ChartColorMode`](/api/metrics#chart-color-mode)
  Strategy used to assign chart colors. Optional.

- **`ui_chart_color_base`** [`ChartColor`](/api/metrics#chart-color)
  Base color used by intensity mode. Optional.

- **`ui_chart_color_rules`** `object[] | null`
  Ordered value-to-color rules used by value mode. Optional.

- **`ui_chart_show_alerts`** `boolean`
  Whether the chart displays alert markers. Optional.

- **`ui_chart_show_monitors`** `boolean`
  Whether the chart displays monitor thresholds. Optional.

- **`ui_chart_show_trends`** `boolean`
  Whether the chart displays regression trends. Optional.

- **`ui_chart_compact_values`** `boolean`
  Whether chart tooltips round values to compact notation, such as 321.3M instead of the full number. Optional.

- **`ui_chart_y_min`** `number | null`
  Fixed lower bound for the chart's y axis. Null lets the axis fit the data. Optional.

- **`ui_chart_y_max`** `number | null`
  Fixed upper bound for the chart's y axis. Null lets the axis fit the data. Optional.

- **`ui_chart_show_forecast`** `boolean`
  Whether the chart opens with its forecast shown, projecting the fitted trend past now to the saved horizon. Optional.

- **`ui_chart_forecast_horizon`** [`ForecastHorizon`](/api/metrics#forecast-horizon)
  How far past now the chart projects its forecast. The value is relative to when the chart is viewed, so it keeps projecting the same distance ahead as time passes. Optional.

- **`ui_chart_forecast_model`** [`ForecastModel`](/api/metrics#forecast-model)
  Curve the forecast is fitted with. Use `auto` to follow whichever model currently fits the series best. Optional.

- **`ui_value_unit`** `string`
  Unit label displayed with chart values. Optional. Maximum length: `32`.

- **`ui_chart_curve`** [`ChartCurve`](/api/metrics#chart-curve)
  Chart line interpolation style. Optional.

- **`ui_chart_value`** [`MetricChartValue`](/api/metrics#metric-chart-value)
  Aggregation value displayed by default. Optional.

- **`ui_chart_time_range`** [`AnalyticsTimeRange`](/api/metrics#analytics-time-range)
  Time range displayed by default. Optional.

- **`ui_chart_interval`** [`ChartInterval`](/api/metrics#chart-interval)
  Aggregation interval displayed by default. Optional.

- **`ui_chart_custom_range_start_at`** [`ISODateString`](/api/metrics#iso-date-string)
  Start of the custom chart range. Optional.

- **`ui_chart_custom_range_end_at`** [`ISODateString`](/api/metrics#iso-date-string)
  End of the custom chart range. Optional.

- **`ui_chart_max_series`** `integer`
  Maximum number of individual series displayed by default. Optional. Minimum: `1`. Maximum: `50`.

- **`backfill_strategy`** [`BackfillStrategy`](/api/metrics#backfill-strategy)
  Order used to rebuild historical data. Optional.

- **`deleted_at`** `null`
  Send `null` to restore a metric that is scheduled for deletion. The deletion date itself is set by the delete endpoint and cannot be written here. Optional.

### Response

Your metric has been updated and is calculating historical data

```ts
{
  message: string;
  data: Metric;
  status: 200;
  error: null;
  pagination: null;
  endpoint: string;
}
```

### Comments

- Field references and filters must be compatible with the selected view.
- Changing the metric's data feed rebuilds its historical rollups.
- Custom chart ranges require both dates, with an interval of at least 30 minutes.
- Color-mode configuration must match the selected chart color mode.
- `filters` must be a valid filter expression.
- `timestamp_field` cannot reference `__meta__` metadata.

## Backfill Metric Data

### Endpoint

Backfill a metric's historical data from its view.

```http
POST /v1/projects/:project_id/metrics/:metric_id/backfill
```

**Scope:** `metrics:write`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

### Response

Your metric data is being rebuilt from its view

```ts
{
  message: string;
  data: Metric;
  status: 200;
  error: null;
  pagination: null;
  endpoint: string;
}
```

## Delete Metric

### Endpoint

Delete a metric.

```http
DELETE /v1/projects/:project_id/metrics/:metric_id
```

**Scope:** `metrics:delete`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

### Response

```ts
{
  message: string;
  data: Metric;
  status: 200;
  error: null;
  pagination: null;
  endpoint: string;
}
```

### Comments

- The metric is hidden immediately and permanently removed once its restore window elapses. Restore it before then by updating it with `deleted_at` set to null.
- Collection and backfill keep running for the whole window, so a restored metric resumes with no gap in its history. Its monitors stop evaluating until it is restored.

## Force Delete Metric

### Endpoint

Delete a metric permanently, without waiting out its restore window.

```http
DELETE /v1/projects/:project_id/metrics/:metric_id/force
```

**Scope:** `metrics:delete`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

### Response

Metric queued for permanent deletion.

```ts
{
  message: string;
  data: null;
  status: 200;
  error: null;
  pagination: null;
  endpoint: string;
}
```

### Comments

- Works on a live metric as well as one already scheduled for deletion.
- Its rollups and monitors are destroyed. The view it reads is not affected, so the metric can be recreated and backfilled.

## List Metric Series

### Endpoint

Retrieve the series discovered for a metric.

```http
GET /v1/projects/:project_id/metrics/:metric_id/series
```

**Scope:** `metrics:read`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

### Query Parameters

- **`limit`** `number`
  Maximum number of items to return. Optional. Defaults to `25`. Minimum: `1`. Maximum: `200`.

- **`after`** `string`
  Cursor from `pagination.next_cursor` of a previous response. Returns the resources after that page. Optional.

- **`before`** `string`
  Cursor from `pagination.prev_cursor` of a previous response. Returns the resources before that page. Optional.

- **`sort`** `string`
  Sort direction for the result set. Optional. Defaults to `"desc"`. Allowed values: `"asc"`, `"desc"`.

- **`order_by`** `string`
  Field used to order the metric series. Optional. Defaults to `"first_seen_at"`. Allowed values: `"first_seen_at"`, `"last_seen_at"`.

- **`search`** `string`
  Substring matched against labels, hashes, and dimension values. Optional. Minimum length: `1`. Maximum length: `128`.

### Response

```ts
{
  message: string;
  data: MetricSeriesRecord[];
  status: 200;
  error: null;
  pagination: Pagination;
  endpoint: string;
}
```

### Comments

- `after` and `before` are mutually exclusive.

## Update Metric Series

### Endpoint

Update the appearance overrides for one metric series.

```http
POST /v1/projects/:project_id/metrics/:metric_id/series/:series_id
```

**Scope:** `metrics:write`

### Path Parameters

- **`project_id`** `string` -- **Required**
  Unique identifier of the project.

- **`metric_id`** `string` -- **Required**
  Unique identifier of the metric.

- **`series_id`** `string` -- **Required**
  Unique identifier of the sery.

### Request Body

- **`color`** [`ChartColor`](/api/metrics#chart-color)
  Color override; null restores automatic color selection. Optional.

- **`pinned`** `boolean`
  Whether the series is pinned ahead of ranked series. Optional.

- **`display_label`** `string | null`
  Display label override; null restores the derived label. Optional.

### Response

Series appearance updated.

```ts
{
  message: string;
  data: MetricSeriesRecord;
  status: 200;
  error: null;
  pagination: null;
  endpoint: string;
}
```

### Comments

- At least one of `color`, `pinned`, or `display_label` must be provided.

