# Components

## Component Model

### Fields

- **`object`** `"component"`

- **`id`** `string`

   Unique identifier, prefixed with `comp_`.

- **`page_id`** `string`

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

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

- **`ui_card_size`** [`ComponentCardSize`](/api/components#component-card-size)

   How much of the page width the component occupies.

- **`ui_sort_index`** `number`

   Position of the component on the page. Lower appears first.

- **`metric`** [`Metric`](/api/metrics#model)

   The metric this component displays.

### Referenced Types

#### ISODateString

`ISODateString`

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

#### ComponentCardSize

`"1/1" | "1/2"`

#### 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`.

## Add Component

### Endpoint

Add a metric to a page.

```http
POST /v1/projects/:project_id/pages/:page_id/components
```

**Scope:** `pages:write`

### Path Parameters

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

- **`page_id`** `string` -- **Required**
  Unique identifier of the page.

### Request Body

- **`ui_sort_index`** `integer`
  Position of the component on the page. Lower appears first. Optional.

- **`ui_card_size`** [`ComponentCardSize`](/api/components#component-card-size)
  How much of the page width the component occupies. Optional.

- **`metric_id`** `string` -- **Required**
  Metric this component displays.

- **`page_id`** `string`
  Page the component is added to. Optional.

### Response

Your component has been created

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

### Comments

- A component is one metric placed on one page. The metric has to belong to the same project.
- The metric must belong to the same project as the page.
- A page holds a limited number of components. Adding one past the limit is rejected.

## Update Component

### Endpoint

Change which metric a component shows, its size, or its position.

```http
POST /v1/projects/:project_id/pages/:page_id/components/:component_id
```

**Scope:** `pages:write`

### Path Parameters

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

- **`page_id`** `string` -- **Required**
  Unique identifier of the page.

- **`component_id`** `string` -- **Required**
  Unique identifier of the component.

### Request Body

- **`ui_sort_index`** `integer`
  Position of the component on the page. Lower appears first. Optional.

- **`ui_card_size`** [`ComponentCardSize`](/api/components#component-card-size)
  How much of the page width the component occupies. Optional.

- **`metric_id`** `string`
  Metric this component displays. Optional.

### Response

Your component has been updated

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

### Comments

- Send only the fields you are changing. Anything omitted keeps its current value.
- Reorder a page by sending a new `ui_sort_index` for each component you are moving.
- A new `metric_id` must belong to the same project as the page.

## Delete Component

### Endpoint

Remove a component from a page.

```http
DELETE /v1/projects/:project_id/pages/:page_id/components/:component_id
```

**Scope:** `pages:write`

### Path Parameters

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

- **`page_id`** `string` -- **Required**
  Unique identifier of the page.

- **`component_id`** `string` -- **Required**
  Unique identifier of the component.

### Response

Your component has been deleted.

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

### Comments

- The metric itself is not affected, only its placement on this page.

