# Create a project monitor

## `POST /v1/projects/{projectId}/monitors`

Creates a project monitor from a runtime template. Requires `monitors:write`. A monitor evaluates a runtime metric on a schedule and fires when the comparison holds; to fire on matching dataset rows instead, create a data reaction at `/v1/projects/{projectId}/reactions`.

### Path parameters

- `projectId` (integer, required): The ID of the project

### Header parameters

- `Authorization` (string, required): `Bearer <token>`. [Authentication](https://spice.ai/docs/cloud/api/management#authentication) lists the tokens it accepts.
- `X-Org-Name` (string, optional): The organization to act on, by handle. Omit it to act on the organization the credential is bound to; sending it blank is a 400, not the same as omitting it. A user credential may name any organization its owner belongs to; a machine credential is pinned to its own. A portal session token is bound to none, so it must send this header on every route but `GET /v1/orgs` (400 `org_assertion_required` otherwise). Pattern: `^[A-Za-z0-9._-]{1,255}$`.

### Request body

Required.

Content type: `application/json`

- `name` (string, required): Display name. Unique, case-insensitively, among the project's live monitors and data reactions — a collision answers 409. Minimum length: `1`. Maximum length: `100`.
- `description` (string): Maximum length: `500`.
- `kind` (string): Optional assertion that `templateId` names a monitor. A value that disagrees with the template is refused rather than ignored; omit it and the template decides. Value: `runtime`.
- `templateId` (string, required): The runtime template the monitor evaluates. `query_latency_p95` is retained for existing monitors but cannot be used to create new ones; use `query_latency_p99`. `container_cpu` is available only on managed projects with a defined CPU limit. A data-reaction template is refused here — create those at `/v1/projects/{projectId}/reactions`. Allowed values: `query_failures`, `query_latency_p95`, `query_latency_p99`, `llm_failures`, `dataset_refresh_errors`, `http_5xx`, `flight_failures`, `memory_working_set`, `container_cpu`, `dataset_status`, `instance_health`.
- `spec` (object, required): Monitor parameters. Which properties apply is decided by `templateId` — each property below names the templates that read it, and a property no monitor template reads is stored rather than rejected. `spec` is shared with data reactions, so it accepts their properties too; `model` is the one that is refused rather than stored.
  - `op` (string, required): Comparison applied to the metric. Required on every monitor spec. `instance_health` requires `GT`. Allowed values: `GT`, `GEQ`, `LT`, `LEQ`, `EQ`, `NEQ`.
  - `threshold` (number, required): Value compared against the metric. HTTP failure monitors count estimated 5xx responses in the selected window. Rate-based conditions use responses per second. `dataset_refresh_errors` counts refresh errors in the window. `query_latency_p99` uses milliseconds. `memory_working_set` uses percent of the instance memory limit. A stored memory threshold above 1000 uses bytes. `container_cpu` uses percent of the defined CPU limit. `dataset_status` compares load-state numbers. `instance_health` requires 0. Every monitor spec requires a threshold.
  - `window` (string): Range evaluated by `query_failures`, `query_latency_p99`, `llm_failures`, `dataset_refresh_errors`, `http_5xx`, `flight_failures`, and `container_cpu`. `memory_working_set` and `dataset_status` read the current value and ignore this field. `instance_health` reads current failure states and uses a fixed five-minute eviction observation window, independent of this field. Data reactions store this field but do not use it. Allowed values: `1m`, `5m`, `15m`, `30m`, `1h`. Default: `5m`.
  - `sustainSecs` (integer): Sustain delay in seconds. Failure monitors default to 0. Other monitors default to 300. Explicit values are preserved. Minimum: `0`. Maximum: `86400`.
  - `severity` (string): Severity the monitor fires at. Recorded on each monitor event and carried into the email or webhook notification. Allowed values: `warn`, `critical`. Default: `critical`.
  - `dataset` (string): Read by `dataset_status`, which watches this one dataset. Omit it to match any dataset in the project. Minimum length: `1`. Maximum length: `128`. Pattern: `^(?!.*\.\.)[A-Za-z_][A-Za-z0-9_.-]*$`.
  - `includeDetails` (boolean): When true, the recorded event and the notification may carry a `details` string quoted from the firing payload when it contains useful information. Off by default, because that payload may be sensitive. A notification's own summary, description, and observed value do not depend on it.
  - `value` (string | number): Read by `dataset_status` for notification wording only, and only when `threshold` is not one of the state numbers above and this names a state. It never changes what the monitor evaluates. Otherwise a data-reaction property.
  - `column` (string): A data-reaction property that no monitor evaluates. Leave it unset — a monitor carrying both `column` and `dataset` has its notification describe that row predicate instead of its own metric comparison. Minimum length: `1`. Maximum length: `64`. Pattern: `^[A-Za-z_][A-Za-z0-9_]*$`.
  - `datasets` (array of string): A data-reaction property that no monitor reads. Maximum items: `20`.
  - `conditions` (array of object): A data-reaction property that no monitor evaluates. Leave it unset — a monitor carrying conditions has its notification describe them instead of its own metric comparison. IS\_NULL and IS\_NOT\_NULL omit value. Maximum items: `20`.
    - `dataset` (string, required): Minimum length: `1`. Maximum length: `128`. Pattern: `^(?!.*\.\.)[A-Za-z_][A-Za-z0-9_.-]*$`.
    - `column` (string, required): Minimum length: `1`. Maximum length: `64`. Pattern: `^[A-Za-z_][A-Za-z0-9_]*$`.
    - `op` (string, required): Allowed values: `EQ`, `NEQ`, `GT`, `GEQ`, `LT`, `LEQ`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `IS_NULL`, `IS_NOT_NULL`.
    - `value` (string | number): Required except for IS\_NULL and IS\_NOT\_NULL.
  - `returnFields` (array of object): Dataset fields returned by generated row-match queries. Include identity and all monitored fields. Maximum items: `20`.
    - `dataset` (string, required)
    - `columns` (array of string, required): Minimum items: `1`. Maximum items: `1000`.
  - `queryLanguage` (string): A data-reaction property that no monitor reads. Allowed values: `cypher`, `gql`.
  - `query` (string): A data-reaction property that no monitor reads. Maximum length: `10000`.
  - `model` (object): Model transform. Data reactions only — sending it with a monitor template is refused with 400, not ignored.
    - `model` (string, required): Minimum length: `1`. Maximum length: `128`.
    - `instructions` (string, required): Minimum length: `1`. Maximum length: `4000`.
- `target` (object): Notification sink. Omit it to email the user the credential belongs to; a machine credential has no user, so its monitors email the organization owner.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer): Organization members to email, by user ID. Maximum items: `50`.
    - `emails` (array of string (email)): Maximum items: `20`.
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri), required): The URL each notification is sent to, using `method`. Must be https and must resolve to a public address. Minimum length: `1`. Maximum length: `2048`.
    - `method` (string): A create that omits it uses POST. An update that omits it keeps the stored method. Allowed values: `POST`, `PUT`, `PATCH`.
    - `token` (string): Bearer token sent with each delivery. Stored encrypted and never returned. Minimum length: `1`. Maximum length: `512`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string, required): Slack conversation id. The organization must already have Slack connected. Minimum length: `9`. Maximum length: `32`. Pattern: `^[CGD][A-Z0-9]{8,31}$`.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `targets` (array of object): Full destination set. When present, this replaces `target` and is the complete list. At most one sink of each type. Minimum items: `1`. Maximum items: `3`.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer): Organization members to email, by user ID. Maximum items: `50`.
    - `emails` (array of string (email)): Maximum items: `20`.
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri), required): The URL each notification is sent to, using `method`. Must be https and must resolve to a public address. Minimum length: `1`. Maximum length: `2048`.
    - `method` (string): A create that omits it uses POST. An update that omits it keeps the stored method. Allowed values: `POST`, `PUT`, `PATCH`.
    - `token` (string): Bearer token sent with each delivery. Stored encrypted and never returned. Minimum length: `1`. Maximum length: `512`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string, required): Slack conversation id. The organization must already have Slack connected. Minimum length: `9`. Maximum length: `32`. Pattern: `^[CGD][A-Z0-9]{8,31}$`.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `recipientUserIds` (array of integer): Legacy spelling of `target.recipientUserIds`, read only when an email target omits its own. Maximum items: `50`.

### Example request

```bash
curl -X POST "https://api.spice.ai/v1/projects/<projectId>/monitors" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string",
    "templateId": "query_failures",
    "spec": {
      "op": "GT",
      "threshold": 0
    }
  }'
```

```http
POST /v1/projects/<projectId>/monitors HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 108

{
  "name": "string",
  "templateId": "query_failures",
  "spec": {
    "op": "GT",
    "threshold": 0
  }
}
```

### Responses

**201 Created**

Monitor created

Content type: `application/json`

A project monitor, as returned by the list, get, create and update operations. Every required property is always present; a nullable one carries null rather than being omitted. `evaluation_unavailable_reason` is present only when an Instance CPU monitor has lost its CPU limit. Fields not listed here are internal to the platform and are not part of the contract.

- `id` (string (uuid), required): Identifier of the monitor or reaction. This is the value the get, update and delete operations take.
- `org_id` (integer, required): Organization that owns the project
- `app_id` (integer, required): Project the monitor or reaction belongs to
- `created_by` (integer | null, required): User who created it, when it was created by a user credential
- `name` (string, required): Display name, unique case-insensitively among the project's live monitors and data reactions
- `description` (string | null, required)
- `kind` (string, required): The monitors endpoints only ever return `runtime`. Value: `runtime`.
- `status` (string, required): Whether it is evaluating. Allowed values: `active`, `disabled`.
- `template_id` (string, required): Template it was created from
- `spec` (object, required): Monitor parameters. Which properties are meaningful is decided by `template_id`. The create operation's request body lists the properties each template reads.
- `target` (object, required): The primary sink (email, then slack, then http). `targets` is the full list. An HTTP sink's `token` is write-only and is never returned.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer)
    - `emails` (array of string (email))
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri) | "", required): The sink's URL. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `method` (string): Allowed values: `POST`, `PUT`, `PATCH`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string | "", required): The Slack channel ID. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `targets` (array of object, required): Every configured sink, ordered email, then slack, then http. `target` is the first of these. An HTTP sink's token is never returned. Minimum items: `1`. Maximum items: `3`.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer)
    - `emails` (array of string (email))
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri) | "", required): The sink's URL. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `method` (string): Allowed values: `POST`, `PUT`, `PATCH`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string | "", required): The Slack channel ID. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `recipient_user_ids` (array of integer, required): Organization members emailed when the monitor fires. Empty when there is no email sink, and for an email sink addressed only by `emails`. When a created email sink named no recipients at all, the API stores the creating user; a machine credential has no user, so it stores none and the monitor emails the organization owner.
- `last_fired_at` (string (date-time) | null, required): When it last fired, or null if it never has
- `last_resolved_at` (string (date-time) | null, required): When it last resolved, or null if it never has
- `created_at` (string (date-time), required)
- `updated_at` (string (date-time), required)
- `evaluation_unavailable_reason` (string): Present when an existing Instance CPU monitor cannot evaluate because its CPU limit was removed. Value: `cpu_limit_missing`.

**400 Bad Request**

Invalid request body or project ID

**401 Unauthorized**

Unauthorized

**403 Forbidden**

Insufficient scope

**404 Not Found**

Project not found, or the template is not available for this project (`code` is `monitor_template_unavailable`). Monitors run only on managed projects, and only released templates are available unless the organization has early access.

**409 Conflict**

A live monitor or data reaction in this project already has this name

**413 Content Too Large**

Request body too large

**422 Unprocessable Content**

Slack is not connected for the organization

**500 Internal Server Error**

Internal server error

**502 Bad Gateway**

Failed to provision monitor

## `POST /v1/orgs/{orgId}/projects/{projectId}/monitors`

The org is `orgId` in the path. Creates a project monitor from a runtime template. Requires `monitors:write`. A monitor evaluates a runtime metric on a schedule and fires when the comparison holds; to fire on matching dataset rows instead, create a data reaction at `/v1/projects/{projectId}/reactions`.

### Path parameters

- `orgId` (integer, required): The org id from GET /v1/orgs. Minimum: `1`.
- `projectId` (integer, required): The ID of the project

### Header parameters

- `Authorization` (string, required): `Bearer <token>`. [Authentication](https://spice.ai/docs/cloud/api/management#authentication) lists the tokens it accepts.
- `X-Org-Name` (string, optional): When present, X-Org-Name must name the same org as orgId. Otherwise the request returns org\_path\_mismatch (400). Pattern: `^[A-Za-z0-9._-]{1,255}$`.

### Request body

Required.

Content type: `application/json`

- `name` (string, required): Display name. Unique, case-insensitively, among the project's live monitors and data reactions — a collision answers 409. Minimum length: `1`. Maximum length: `100`.
- `description` (string): Maximum length: `500`.
- `kind` (string): Optional assertion that `templateId` names a monitor. A value that disagrees with the template is refused rather than ignored; omit it and the template decides. Value: `runtime`.
- `templateId` (string, required): The runtime template the monitor evaluates. `query_latency_p95` is retained for existing monitors but cannot be used to create new ones; use `query_latency_p99`. `container_cpu` is available only on managed projects with a defined CPU limit. A data-reaction template is refused here — create those at `/v1/projects/{projectId}/reactions`. Allowed values: `query_failures`, `query_latency_p95`, `query_latency_p99`, `llm_failures`, `dataset_refresh_errors`, `http_5xx`, `flight_failures`, `memory_working_set`, `container_cpu`, `dataset_status`, `instance_health`.
- `spec` (object, required): Monitor parameters. Which properties apply is decided by `templateId` — each property below names the templates that read it, and a property no monitor template reads is stored rather than rejected. `spec` is shared with data reactions, so it accepts their properties too; `model` is the one that is refused rather than stored.
  - `op` (string, required): Comparison applied to the metric. Required on every monitor spec. `instance_health` requires `GT`. Allowed values: `GT`, `GEQ`, `LT`, `LEQ`, `EQ`, `NEQ`.
  - `threshold` (number, required): Value compared against the metric. HTTP failure monitors count estimated 5xx responses in the selected window. Rate-based conditions use responses per second. `dataset_refresh_errors` counts refresh errors in the window. `query_latency_p99` uses milliseconds. `memory_working_set` uses percent of the instance memory limit. A stored memory threshold above 1000 uses bytes. `container_cpu` uses percent of the defined CPU limit. `dataset_status` compares load-state numbers. `instance_health` requires 0. Every monitor spec requires a threshold.
  - `window` (string): Range evaluated by `query_failures`, `query_latency_p99`, `llm_failures`, `dataset_refresh_errors`, `http_5xx`, `flight_failures`, and `container_cpu`. `memory_working_set` and `dataset_status` read the current value and ignore this field. `instance_health` reads current failure states and uses a fixed five-minute eviction observation window, independent of this field. Data reactions store this field but do not use it. Allowed values: `1m`, `5m`, `15m`, `30m`, `1h`. Default: `5m`.
  - `sustainSecs` (integer): Sustain delay in seconds. Failure monitors default to 0. Other monitors default to 300. Explicit values are preserved. Minimum: `0`. Maximum: `86400`.
  - `severity` (string): Severity the monitor fires at. Recorded on each monitor event and carried into the email or webhook notification. Allowed values: `warn`, `critical`. Default: `critical`.
  - `dataset` (string): Read by `dataset_status`, which watches this one dataset. Omit it to match any dataset in the project. Minimum length: `1`. Maximum length: `128`. Pattern: `^(?!.*\.\.)[A-Za-z_][A-Za-z0-9_.-]*$`.
  - `includeDetails` (boolean): When true, the recorded event and the notification may carry a `details` string quoted from the firing payload when it contains useful information. Off by default, because that payload may be sensitive. A notification's own summary, description, and observed value do not depend on it.
  - `value` (string | number): Read by `dataset_status` for notification wording only, and only when `threshold` is not one of the state numbers above and this names a state. It never changes what the monitor evaluates. Otherwise a data-reaction property.
  - `column` (string): A data-reaction property that no monitor evaluates. Leave it unset — a monitor carrying both `column` and `dataset` has its notification describe that row predicate instead of its own metric comparison. Minimum length: `1`. Maximum length: `64`. Pattern: `^[A-Za-z_][A-Za-z0-9_]*$`.
  - `datasets` (array of string): A data-reaction property that no monitor reads. Maximum items: `20`.
  - `conditions` (array of object): A data-reaction property that no monitor evaluates. Leave it unset — a monitor carrying conditions has its notification describe them instead of its own metric comparison. IS\_NULL and IS\_NOT\_NULL omit value. Maximum items: `20`.
    - `dataset` (string, required): Minimum length: `1`. Maximum length: `128`. Pattern: `^(?!.*\.\.)[A-Za-z_][A-Za-z0-9_.-]*$`.
    - `column` (string, required): Minimum length: `1`. Maximum length: `64`. Pattern: `^[A-Za-z_][A-Za-z0-9_]*$`.
    - `op` (string, required): Allowed values: `EQ`, `NEQ`, `GT`, `GEQ`, `LT`, `LEQ`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `IS_NULL`, `IS_NOT_NULL`.
    - `value` (string | number): Required except for IS\_NULL and IS\_NOT\_NULL.
  - `returnFields` (array of object): Dataset fields returned by generated row-match queries. Include identity and all monitored fields. Maximum items: `20`.
    - `dataset` (string, required)
    - `columns` (array of string, required): Minimum items: `1`. Maximum items: `1000`.
  - `queryLanguage` (string): A data-reaction property that no monitor reads. Allowed values: `cypher`, `gql`.
  - `query` (string): A data-reaction property that no monitor reads. Maximum length: `10000`.
  - `model` (object): Model transform. Data reactions only — sending it with a monitor template is refused with 400, not ignored.
    - `model` (string, required): Minimum length: `1`. Maximum length: `128`.
    - `instructions` (string, required): Minimum length: `1`. Maximum length: `4000`.
- `target` (object): Notification sink. Omit it to email the user the credential belongs to; a machine credential has no user, so its monitors email the organization owner.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer): Organization members to email, by user ID. Maximum items: `50`.
    - `emails` (array of string (email)): Maximum items: `20`.
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri), required): The URL each notification is sent to, using `method`. Must be https and must resolve to a public address. Minimum length: `1`. Maximum length: `2048`.
    - `method` (string): A create that omits it uses POST. An update that omits it keeps the stored method. Allowed values: `POST`, `PUT`, `PATCH`.
    - `token` (string): Bearer token sent with each delivery. Stored encrypted and never returned. Minimum length: `1`. Maximum length: `512`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string, required): Slack conversation id. The organization must already have Slack connected. Minimum length: `9`. Maximum length: `32`. Pattern: `^[CGD][A-Z0-9]{8,31}$`.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `targets` (array of object): Full destination set. When present, this replaces `target` and is the complete list. At most one sink of each type. Minimum items: `1`. Maximum items: `3`.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer): Organization members to email, by user ID. Maximum items: `50`.
    - `emails` (array of string (email)): Maximum items: `20`.
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri), required): The URL each notification is sent to, using `method`. Must be https and must resolve to a public address. Minimum length: `1`. Maximum length: `2048`.
    - `method` (string): A create that omits it uses POST. An update that omits it keeps the stored method. Allowed values: `POST`, `PUT`, `PATCH`.
    - `token` (string): Bearer token sent with each delivery. Stored encrypted and never returned. Minimum length: `1`. Maximum length: `512`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string, required): Slack conversation id. The organization must already have Slack connected. Minimum length: `9`. Maximum length: `32`. Pattern: `^[CGD][A-Z0-9]{8,31}$`.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `recipientUserIds` (array of integer): Legacy spelling of `target.recipientUserIds`, read only when an email target omits its own. Maximum items: `50`.

### Example request

```bash
curl -X POST "https://api.spice.ai/v1/orgs/<orgId>/projects/<projectId>/monitors" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string",
    "templateId": "query_failures",
    "spec": {
      "op": "GT",
      "threshold": 0
    }
  }'
```

```http
POST /v1/orgs/<orgId>/projects/<projectId>/monitors HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 108

{
  "name": "string",
  "templateId": "query_failures",
  "spec": {
    "op": "GT",
    "threshold": 0
  }
}
```

### Responses

**201 Created**

Monitor created

Content type: `application/json`

A project monitor, as returned by the list, get, create and update operations. Every required property is always present; a nullable one carries null rather than being omitted. `evaluation_unavailable_reason` is present only when an Instance CPU monitor has lost its CPU limit. Fields not listed here are internal to the platform and are not part of the contract.

- `id` (string (uuid), required): Identifier of the monitor or reaction. This is the value the get, update and delete operations take.
- `org_id` (integer, required): Organization that owns the project
- `app_id` (integer, required): Project the monitor or reaction belongs to
- `created_by` (integer | null, required): User who created it, when it was created by a user credential
- `name` (string, required): Display name, unique case-insensitively among the project's live monitors and data reactions
- `description` (string | null, required)
- `kind` (string, required): The monitors endpoints only ever return `runtime`. Value: `runtime`.
- `status` (string, required): Whether it is evaluating. Allowed values: `active`, `disabled`.
- `template_id` (string, required): Template it was created from
- `spec` (object, required): Monitor parameters. Which properties are meaningful is decided by `template_id`. The create operation's request body lists the properties each template reads.
- `target` (object, required): The primary sink (email, then slack, then http). `targets` is the full list. An HTTP sink's `token` is write-only and is never returned.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer)
    - `emails` (array of string (email))
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri) | "", required): The sink's URL. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `method` (string): Allowed values: `POST`, `PUT`, `PATCH`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string | "", required): The Slack channel ID. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `targets` (array of object, required): Every configured sink, ordered email, then slack, then http. `target` is the first of these. An HTTP sink's token is never returned. Minimum items: `1`. Maximum items: `3`.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer)
    - `emails` (array of string (email))
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri) | "", required): The sink's URL. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `method` (string): Allowed values: `POST`, `PUT`, `PATCH`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string | "", required): The Slack channel ID. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `recipient_user_ids` (array of integer, required): Organization members emailed when the monitor fires. Empty when there is no email sink, and for an email sink addressed only by `emails`. When a created email sink named no recipients at all, the API stores the creating user; a machine credential has no user, so it stores none and the monitor emails the organization owner.
- `last_fired_at` (string (date-time) | null, required): When it last fired, or null if it never has
- `last_resolved_at` (string (date-time) | null, required): When it last resolved, or null if it never has
- `created_at` (string (date-time), required)
- `updated_at` (string (date-time), required)
- `evaluation_unavailable_reason` (string): Present when an existing Instance CPU monitor cannot evaluate because its CPU limit was removed. Value: `cpu_limit_missing`.

**400 Bad Request**

Invalid request body or project ID. orgId is not a valid org id (`invalid_org_id`), or X-Org-Name does not name that org (`org_path_mismatch`).

**401 Unauthorized**

Unauthorized

**403 Forbidden**

Insufficient scope. The caller is not a member of the org (`org_forbidden`). A machine credential named a different org (`org_assertion_mismatch`). The org is deleted (`org_deleted`).

**404 Not Found**

Project not found, or the template is not available for this project (`code` is `monitor_template_unavailable`). Monitors run only on managed projects, and only released templates are available unless the organization has early access.

**409 Conflict**

A live monitor or data reaction in this project already has this name

**413 Content Too Large**

Request body too large

**422 Unprocessable Content**

Slack is not connected for the organization

**500 Internal Server Error**

Internal server error

**502 Bad Gateway**

Failed to provision monitor

## `POST /v1/apps/{appId}/monitors` (deprecated)

Legacy alias of `/v1/projects/{projectId}/monitors` — projects were previously called apps. Creates a project monitor from a runtime template. Requires `monitors:write`. A monitor evaluates a runtime metric on a schedule and fires when the comparison holds; to fire on matching dataset rows instead, create a data reaction at `/v1/projects/{projectId}/reactions`.

### Path parameters

- `appId` (integer, required): The ID of the project

### Header parameters

- `Authorization` (string, required): `Bearer <token>`. [Authentication](https://spice.ai/docs/cloud/api/management#authentication) lists the tokens it accepts.
- `X-Org-Name` (string, optional): The organization to act on, by handle. Omit it to act on the organization the credential is bound to; sending it blank is a 400, not the same as omitting it. A user credential may name any organization its owner belongs to; a machine credential is pinned to its own. A portal session token is bound to none, so it must send this header on every route but `GET /v1/orgs` (400 `org_assertion_required` otherwise). Pattern: `^[A-Za-z0-9._-]{1,255}$`.

### Request body

Required.

Content type: `application/json`

- `name` (string, required): Display name. Unique, case-insensitively, among the project's live monitors and data reactions — a collision answers 409. Minimum length: `1`. Maximum length: `100`.
- `description` (string): Maximum length: `500`.
- `kind` (string): Optional assertion that `templateId` names a monitor. A value that disagrees with the template is refused rather than ignored; omit it and the template decides. Value: `runtime`.
- `templateId` (string, required): The runtime template the monitor evaluates. `query_latency_p95` is retained for existing monitors but cannot be used to create new ones; use `query_latency_p99`. `container_cpu` is available only on managed projects with a defined CPU limit. A data-reaction template is refused here — create those at `/v1/projects/{projectId}/reactions`. Allowed values: `query_failures`, `query_latency_p95`, `query_latency_p99`, `llm_failures`, `dataset_refresh_errors`, `http_5xx`, `flight_failures`, `memory_working_set`, `container_cpu`, `dataset_status`, `instance_health`.
- `spec` (object, required): Monitor parameters. Which properties apply is decided by `templateId` — each property below names the templates that read it, and a property no monitor template reads is stored rather than rejected. `spec` is shared with data reactions, so it accepts their properties too; `model` is the one that is refused rather than stored.
  - `op` (string, required): Comparison applied to the metric. Required on every monitor spec. `instance_health` requires `GT`. Allowed values: `GT`, `GEQ`, `LT`, `LEQ`, `EQ`, `NEQ`.
  - `threshold` (number, required): Value compared against the metric. HTTP failure monitors count estimated 5xx responses in the selected window. Rate-based conditions use responses per second. `dataset_refresh_errors` counts refresh errors in the window. `query_latency_p99` uses milliseconds. `memory_working_set` uses percent of the instance memory limit. A stored memory threshold above 1000 uses bytes. `container_cpu` uses percent of the defined CPU limit. `dataset_status` compares load-state numbers. `instance_health` requires 0. Every monitor spec requires a threshold.
  - `window` (string): Range evaluated by `query_failures`, `query_latency_p99`, `llm_failures`, `dataset_refresh_errors`, `http_5xx`, `flight_failures`, and `container_cpu`. `memory_working_set` and `dataset_status` read the current value and ignore this field. `instance_health` reads current failure states and uses a fixed five-minute eviction observation window, independent of this field. Data reactions store this field but do not use it. Allowed values: `1m`, `5m`, `15m`, `30m`, `1h`. Default: `5m`.
  - `sustainSecs` (integer): Sustain delay in seconds. Failure monitors default to 0. Other monitors default to 300. Explicit values are preserved. Minimum: `0`. Maximum: `86400`.
  - `severity` (string): Severity the monitor fires at. Recorded on each monitor event and carried into the email or webhook notification. Allowed values: `warn`, `critical`. Default: `critical`.
  - `dataset` (string): Read by `dataset_status`, which watches this one dataset. Omit it to match any dataset in the project. Minimum length: `1`. Maximum length: `128`. Pattern: `^(?!.*\.\.)[A-Za-z_][A-Za-z0-9_.-]*$`.
  - `includeDetails` (boolean): When true, the recorded event and the notification may carry a `details` string quoted from the firing payload when it contains useful information. Off by default, because that payload may be sensitive. A notification's own summary, description, and observed value do not depend on it.
  - `value` (string | number): Read by `dataset_status` for notification wording only, and only when `threshold` is not one of the state numbers above and this names a state. It never changes what the monitor evaluates. Otherwise a data-reaction property.
  - `column` (string): A data-reaction property that no monitor evaluates. Leave it unset — a monitor carrying both `column` and `dataset` has its notification describe that row predicate instead of its own metric comparison. Minimum length: `1`. Maximum length: `64`. Pattern: `^[A-Za-z_][A-Za-z0-9_]*$`.
  - `datasets` (array of string): A data-reaction property that no monitor reads. Maximum items: `20`.
  - `conditions` (array of object): A data-reaction property that no monitor evaluates. Leave it unset — a monitor carrying conditions has its notification describe them instead of its own metric comparison. IS\_NULL and IS\_NOT\_NULL omit value. Maximum items: `20`.
    - `dataset` (string, required): Minimum length: `1`. Maximum length: `128`. Pattern: `^(?!.*\.\.)[A-Za-z_][A-Za-z0-9_.-]*$`.
    - `column` (string, required): Minimum length: `1`. Maximum length: `64`. Pattern: `^[A-Za-z_][A-Za-z0-9_]*$`.
    - `op` (string, required): Allowed values: `EQ`, `NEQ`, `GT`, `GEQ`, `LT`, `LEQ`, `CONTAINS`, `STARTS_WITH`, `ENDS_WITH`, `IS_NULL`, `IS_NOT_NULL`.
    - `value` (string | number): Required except for IS\_NULL and IS\_NOT\_NULL.
  - `returnFields` (array of object): Dataset fields returned by generated row-match queries. Include identity and all monitored fields. Maximum items: `20`.
    - `dataset` (string, required)
    - `columns` (array of string, required): Minimum items: `1`. Maximum items: `1000`.
  - `queryLanguage` (string): A data-reaction property that no monitor reads. Allowed values: `cypher`, `gql`.
  - `query` (string): A data-reaction property that no monitor reads. Maximum length: `10000`.
  - `model` (object): Model transform. Data reactions only — sending it with a monitor template is refused with 400, not ignored.
    - `model` (string, required): Minimum length: `1`. Maximum length: `128`.
    - `instructions` (string, required): Minimum length: `1`. Maximum length: `4000`.
- `target` (object): Notification sink. Omit it to email the user the credential belongs to; a machine credential has no user, so its monitors email the organization owner.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer): Organization members to email, by user ID. Maximum items: `50`.
    - `emails` (array of string (email)): Maximum items: `20`.
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri), required): The URL each notification is sent to, using `method`. Must be https and must resolve to a public address. Minimum length: `1`. Maximum length: `2048`.
    - `method` (string): A create that omits it uses POST. An update that omits it keeps the stored method. Allowed values: `POST`, `PUT`, `PATCH`.
    - `token` (string): Bearer token sent with each delivery. Stored encrypted and never returned. Minimum length: `1`. Maximum length: `512`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string, required): Slack conversation id. The organization must already have Slack connected. Minimum length: `9`. Maximum length: `32`. Pattern: `^[CGD][A-Z0-9]{8,31}$`.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `targets` (array of object): Full destination set. When present, this replaces `target` and is the complete list. At most one sink of each type. Minimum items: `1`. Maximum items: `3`.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer): Organization members to email, by user ID. Maximum items: `50`.
    - `emails` (array of string (email)): Maximum items: `20`.
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri), required): The URL each notification is sent to, using `method`. Must be https and must resolve to a public address. Minimum length: `1`. Maximum length: `2048`.
    - `method` (string): A create that omits it uses POST. An update that omits it keeps the stored method. Allowed values: `POST`, `PUT`, `PATCH`.
    - `token` (string): Bearer token sent with each delivery. Stored encrypted and never returned. Minimum length: `1`. Maximum length: `512`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string, required): Slack conversation id. The organization must already have Slack connected. Minimum length: `9`. Maximum length: `32`. Pattern: `^[CGD][A-Z0-9]{8,31}$`.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `recipientUserIds` (array of integer): Legacy spelling of `target.recipientUserIds`, read only when an email target omits its own. Maximum items: `50`.

### Example request

```bash
curl -X POST "https://api.spice.ai/v1/apps/<appId>/monitors" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string",
    "templateId": "query_failures",
    "spec": {
      "op": "GT",
      "threshold": 0
    }
  }'
```

```http
POST /v1/apps/<appId>/monitors HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 108

{
  "name": "string",
  "templateId": "query_failures",
  "spec": {
    "op": "GT",
    "threshold": 0
  }
}
```

### Responses

**201 Created**

Monitor created

Content type: `application/json`

A project monitor, as returned by the list, get, create and update operations. Every required property is always present; a nullable one carries null rather than being omitted. `evaluation_unavailable_reason` is present only when an Instance CPU monitor has lost its CPU limit. Fields not listed here are internal to the platform and are not part of the contract.

- `id` (string (uuid), required): Identifier of the monitor or reaction. This is the value the get, update and delete operations take.
- `org_id` (integer, required): Organization that owns the project
- `app_id` (integer, required): Project the monitor or reaction belongs to
- `created_by` (integer | null, required): User who created it, when it was created by a user credential
- `name` (string, required): Display name, unique case-insensitively among the project's live monitors and data reactions
- `description` (string | null, required)
- `kind` (string, required): The monitors endpoints only ever return `runtime`. Value: `runtime`.
- `status` (string, required): Whether it is evaluating. Allowed values: `active`, `disabled`.
- `template_id` (string, required): Template it was created from
- `spec` (object, required): Monitor parameters. Which properties are meaningful is decided by `template_id`. The create operation's request body lists the properties each template reads.
- `target` (object, required): The primary sink (email, then slack, then http). `targets` is the full list. An HTTP sink's `token` is write-only and is never returned.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer)
    - `emails` (array of string (email))
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri) | "", required): The sink's URL. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `method` (string): Allowed values: `POST`, `PUT`, `PATCH`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string | "", required): The Slack channel ID. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `targets` (array of object, required): Every configured sink, ordered email, then slack, then http. `target` is the first of these. An HTTP sink's token is never returned. Minimum items: `1`. Maximum items: `3`.

  One of:
  - **type: email** (object)
    - `type` (string, required): Value: `email`.
    - `recipientUserIds` (array of integer)
    - `emails` (array of string (email))
  - **type: http** (object)
    - `type` (string, required): Value: `http`.
    - `url` (string (uri) | "", required): The sink's URL. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `method` (string): Allowed values: `POST`, `PUT`, `PATCH`.
  - **type: slack** (object)
    - `type` (string, required): Value: `slack`.
    - `channelId` (string | "", required): The Slack channel ID. An empty string means the stored sink no longer passes validation. Update the sink to replace it.
    - `channelName` (string): Minimum length: `1`. Maximum length: `80`.
- `recipient_user_ids` (array of integer, required): Organization members emailed when the monitor fires. Empty when there is no email sink, and for an email sink addressed only by `emails`. When a created email sink named no recipients at all, the API stores the creating user; a machine credential has no user, so it stores none and the monitor emails the organization owner.
- `last_fired_at` (string (date-time) | null, required): When it last fired, or null if it never has
- `last_resolved_at` (string (date-time) | null, required): When it last resolved, or null if it never has
- `created_at` (string (date-time), required)
- `updated_at` (string (date-time), required)
- `evaluation_unavailable_reason` (string): Present when an existing Instance CPU monitor cannot evaluate because its CPU limit was removed. Value: `cpu_limit_missing`.

**400 Bad Request**

Invalid request body or project ID

**401 Unauthorized**

Unauthorized

**403 Forbidden**

Insufficient scope

**404 Not Found**

Project not found, or the template is not available for this project (`code` is `monitor_template_unavailable`). Monitors run only on managed projects, and only released templates are available unless the organization has early access.

**409 Conflict**

A live monitor or data reaction in this project already has this name

**413 Content Too Large**

Request body too large

**422 Unprocessable Content**

Slack is not connected for the organization

**500 Internal Server Error**

Internal server error

**502 Bad Gateway**

Failed to provision monitor

OpenAPI: [api.spice.ai/openapi.json](https://api.spice.ai/openapi.json)
