# Detection Rules

## Create a new detection rule

<mark style="color:green;">**`POST`**</mark> `/v1/detection_rule`

Create a new detection rule with the specified data.

If the detection rule is active, it will be immediately scheduled for backfill and execution.

**Body**

<table><thead><tr><th width="273">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>tenant_id</code> <mark style="color:red;">required</mark></td><td>string</td><td>Unique identifier for the tenant</td></tr><tr><td><code>name</code> <mark style="color:red;">required</mark></td><td>string</td><td>Name of the detection rule</td></tr><tr><td><code>description</code> <mark style="color:red;">required</mark></td><td>string</td><td>Description of the detection rule</td></tr><tr><td><code>time_range_s</code> <mark style="color:red;">required</mark></td><td>number</td><td>Lookback period (in seconds). Must be minute granuarlity (for example, 60 seconds is valid, but 30 seconds is not).</td></tr><tr><td><code>run_frequency_s</code> <mark style="color:red;">required</mark></td><td>number</td><td>How frequently to run the detection rule (in seconds). Must be minute granularity and &#x3C;= <code>time_range_s</code>.</td></tr><tr><td><code>enabled_state_override</code> <mark style="color:red;">required</mark></td><td>"Active", "Staging", or "Paused"</td><td>Whether the detection rule runs and sends events to event sinks</td></tr><tr><td><code>severity</code> <mark style="color:red;">required</mark></td><td>See <a data-mention href="#detection-severity">#detection-severity</a></td><td>The severity of the detection</td></tr><tr><td><code>query_text</code> <mark style="color:red;">required</mark></td><td>string</td><td>Query for the detection rule</td></tr><tr><td><code>event_sink_ids</code> <mark style="color:red;">required</mark></td><td>list of strings</td><td>Event sinks to send event alerts to</td></tr><tr><td><code>alert_per_row</code></td><td>boolean</td><td>If <code>true</code>, emit one detection alert per row of the query's results table instead of a single alert containing the whole (truncated) table. Defaults to <code>false</code>.</td></tr><tr><td><code>tags</code></td><td>list of strings</td><td>Associated tags for the detection rule. Scanner has default <a data-mention href="/pages/GFF5XfmxpQ3JMGbtLZN3">/pages/GFF5XfmxpQ3JMGbtLZN3</a> that you can use or you can create your own.</td></tr><tr><td><code>sync_key</code></td><td>string</td><td>Sync key, used by automatic detection rule syncers</td></tr><tr><td><code>alert_template</code></td><td>object</td><td>Custom alert formatting template. See <a data-mention href="#alert-template">#alert-template</a> below.</td></tr></tbody></table>

**Example**

{% code overflow="wrap" %}

```bash
curl $API_BASE/v1/detection_rule \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-X POST \
-d '{
    "tenant_id": "00000000-0000-0000-0000-000000000000",
    "name": "Errors",
    "description": "Errors in application logs",
    "time_range_s": 300,
    "run_frequency_s": 300,
    "enabled_state_override": "Active",
    "severity": "Informational",
    "query_text": "error | count | where @q.count > 100",
    "tags": ["scanner.error"],
    "event_sink_ids": []
}'
```

{% endcode %}

**Response**

Returns the newly created detection rule.

```json
{
  "detection_rule": {
    "id": "d87284f8-b0f3-4464-9ba9-258c0e585d09",
    "sync_key": null,
    "prepared_query_id": "b8aa9bb6-de1e-4ef8-82bb-29974a1e4ff2",
    "detection_rule_sync_id": null,
    "query_text": "error | count | where @q.count > 100",
    "tenant_id": "00000000-0000-0000-0000-000000000000",
    "time_range_s": 300,
    "run_frequency_s": 300,
    "debounce": true,
    "alert_per_row": false,
    "author_user_id": null,
    "name": "Errors",
    "description": "Errors in application logs",
    "enabled": true,
    "enabled_override": null,
    "severity": "Informational",
    "alert_template": null,
    "tags":["scanner.error"],
    "created_at": "2024-05-09T01:07:24Z",
    "updated_at": "2024-05-09T01:07:24Z",
    "event_sink_ids": [],
    "last_alerted_at": null
  }
}
```

## List detection rules

<mark style="color:blue;">**`GET`**</mark> `/v1/detection_rule`

List all detection rules for a tenant.

**Query parameters**

<table><thead><tr><th width="272">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>tenant_id</code> <mark style="color:red;">required</mark></td><td>string</td><td>Unique identifier for the tenant</td></tr><tr><td><code>pagination[page_size]</code></td><td>number</td><td>Maximum number of results to return in a page. Defaults to 50</td></tr><tr><td><code>pagination[page_token]</code></td><td>string</td><td>Cursor for pagination. <code>list_detection_rules</code>returns <code>next_page_token</code> to be used for this field. If the field is not specified, paging will start at the beginning of the list.</td></tr></tbody></table>

**Example**

```bash
curl -G $API_BASE/v1/detection_rule \
--data-urlencode "tenant_id=00000000-0000-0000-0000-000000000001" \
--data-urlencode "pagination[page_size]=5" \
--data-urlencode "pagination[page_token]=1" \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H "Content-Type: application/json"
```

**Response**

Returns a list of detection rule summaries and pagination information. The detection rule summary object is the same as the detection rule object, but it does not include `event_sink_ids`. The pagination information includes the `next_page_token`to use as the pagination cursor. `next_page_token`is null if there are no more remaining pages.

```json
{
  "data": {
    "detection_rules": [
      {
        "id": "d87284f8-b0f3-4464-9ba9-258c0e585d09",
        "sync_key": null,
        "prepared_query_id": "b8aa9bb6-de1e-4ef8-82bb-29974a1e4ff2",
        "detection_rule_sync_id": null,
        "query_text": "error | count | where @q.count > 100",
        "tenant_id": "00000000-0000-0000-0000-000000000000",
        "time_range_s": 300,
        "run_frequency_s": 300,
        "debounce": true,
        "alert_per_row": false,
        "author_user_id": null,
        "name": "Errors",
        "description": "Errors in application logs",
        "enabled_state_override": "Active",
        "enabled_state_synced": null,
        "severity": "Informational",
        "alert_template": null,
        "tags":["scanner.error"],
        "created_at": "2024-05-09T01:07:24Z",
        "updated_at": "2024-05-09T01:07:24Z",
        "last_alerted_at": null
      }
    ]
  },
  "pagination": {
    "next_page_token": null
  }
}
```

## Get a detection rule

<mark style="color:blue;">**`GET`**</mark> `/v1/detection_rule/{id}`

Get the detection rule with the given id.

**Example**

```bash
curl $API_BASE/v1/detection_rule/d87284f8-b0f3-4464-9ba9-258c0e585d09 \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-X GET
```

**Response**

Returns the detection rule.

```json
{
  "detection_rule": {
    "id": "d87284f8-b0f3-4464-9ba9-258c0e585d09",
    "sync_key": null,
    "prepared_query_id": "b8aa9bb6-de1e-4ef8-82bb-29974a1e4ff2",
    "detection_rule_sync_id": null,
    "query_text": "error | count | where @q.count > 100",
    "tenant_id": "00000000-0000-0000-0000-000000000000",
    "time_range_s": 300,
    "run_frequency_s": 300,
    "debounce": true,
    "alert_per_row": false,
    "author_user_id": null,
    "name": "Errors",
    "description": "Errors in application logs",
        "enabled_state_override": "Active",
        "enabled_state_synced": null,
    "severity": "Informational",
    "alert_template": null,
    "tags":["scanner.error"],
    "created_at": "2024-05-09T01:07:24Z",
    "updated_at": "2024-05-09T01:07:24Z",
    "event_sink_ids": [],
    "last_alerted_at": null
  }
}
```

## Update a detection rule

<mark style="color:orange;">**`PUT`**</mark> `/v1/detection_rule/{id}`

Update the detection rule with the given id. If the rule is synced from GitHub (in which case `detection_rule_sync_id` will be non-null), then `enable_override` is the *only* field that can be updated.

**Body**

| Name                                          | Type                                                     | Description                                                                                                                                                                                                                    |
| --------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id` <mark style="color:red;">required</mark> | string                                                   | Unique identifier for the detection rule                                                                                                                                                                                       |
| `name`                                        | string                                                   | Update the name of the detection rule                                                                                                                                                                                          |
| `description`                                 | string                                                   | Update the description of the detection rule                                                                                                                                                                                   |
| `time_range_s`                                | number                                                   | Update the lookback period (in seconds) of the detection rule. Must be minute granularity (for example, 60 seconds is valid, but 30 seconds is not).                                                                           |
| `run_frequency_s`                             | number                                                   | Update the how frequently the detection rule is run (in seconds). Must be minute granularity and <= `time_range_s`.                                                                                                            |
| `alert_per_row`                               | boolean                                                  | If `true`, emit one detection alert per row of the query's results table instead of a single alert containing the whole (truncated) table.                                                                                     |
| `enabled_state_override`                      | `"Active"`, `"Staging"`, `"Paused"`, or `null`           | Enable, enable without sending events, or disable the detection. Overrides `enabled_state_synced` for synced detection rules if non-null.                                                                                      |
| `severity`                                    | See [#detection-severity](#detection-severity "mention") | Update the severity of the detection rule                                                                                                                                                                                      |
| `query_text`                                  | string                                                   | Update the query for the detection rule                                                                                                                                                                                        |
| `tags`                                        | list of strings                                          | Update the tags for the detection rule. Scanner has default [MITRE Tags](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/mitre-tags.md) that you can use or you can create your own. |
| `event_sink_ids`                              | list of strings                                          | Update the event sinks for the detection rule                                                                                                                                                                                  |
| `sync_key`                                    | string                                                   | Update the sync key for the detection rule                                                                                                                                                                                     |
| `alert_template`                              | object or null                                           | Update the alert template. Set to `null` to remove. See [#alert-template](#alert-template "mention") below.                                                                                                                    |

**Example**

```bash
curl $API_BASE/v1/detection_rule/d87284f8-b0f3-4464-9ba9-258c0e585d09 \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-X PUT \
-d '{
    "id": "d87284f8-b0f3-4464-9ba9-258c0e585d09",
    "description": "Detect errors in application logs"
}'
```

**Response**

Returns the updated detection rule.

```json
{
  "detection_rule": {
    "id": "d87284f8-b0f3-4464-9ba9-258c0e585d09",
    "sync_key": null,
    "prepared_query_id": "b8aa9bb6-de1e-4ef8-82bb-29974a1e4ff2",
    "detection_rule_sync_id": null,
    "query_text": "error | count | where @q.count > 100",
    "tenant_id": "00000000-0000-0000-0000-000000000000",
    "time_range_s": 300,
    "run_frequency_s": 300,
    "debounce": true,
    "alert_per_row": false,
    "author_user_id": null,
    "name": "Errors",
    "description": "Detect errors in application logs",
    "enabled_state_override": "Active",
    "enabled_state_synced": null,
    "severity": "Informational",
    "alert_template": null,
    "tags":["scanner.error"],
    "created_at": "2024-05-09T01:07:24Z",
    "updated_at": "2024-05-09T01:07:24Z",
    "event_sink_ids": [],
    "last_alerted_at": null
  }
}
```

## Delete a detection rule

<mark style="color:red;">**`DELETE`**</mark> `/v1/detection_rule/{id}`

Delete the detection rule with the given id.

**Example**

```bash
curl $API_BASE/v1/detection_rule/123e4567-e89b-12d3-a456-426614174000 \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-X DELETE
```

**Response**

Returns the `id` and `tenant_id` for the deleted detection rule.

```json
{
  "id": "d87284f8-b0f3-4464-9ba9-258c0e585d09",
  "tenant_id": "00000000-0000-0000-0000-000000000000"
}
```

## Alert template

You can customize detection alert formatting by providing an `alert_template` object with the following fields:

| Field     | Type  | Description                                            |
| --------- | ----- | ------------------------------------------------------ |
| `info`    | array | Key-value fields displayed in the alert                |
| `actions` | array | Buttons (Slack) or links (Markdown) shown in the alert |

**`info`** items appear as key-value information in the alert. Each item has:

| Field           | Type    | Description                                                                                                                                                                                                                                                        |
| --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `label`         | string  | Display label for this field                                                                                                                                                                                                                                       |
| `value`         | string  | Value to display. Supports `{{field_name}}` template syntax to reference fields from query results.                                                                                                                                                                |
| `use_for_dedup` | boolean | If `true`, this field's value is used as a deduplication key. When multiple alerts share the same dedup key values, they are grouped together so you receive a single notification rather than repeated alerts for the same underlying issue. Defaults to `false`. |

**`actions`** items appear as buttons in Slack and links in Markdown. Each item has:

| Field   | Type   | Description                                                                                                                                         |
| ------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `label` | string | Button or link text                                                                                                                                 |
| `value` | string | URL for the action. If the value is not a valid URL, it will appear as text instead of a button or link. Supports `{{field_name}}` template syntax. |

See [Detection Alert Formatting](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-alert-formatting.md) for more details on templating.

**Example**

```json
"alert_template": {
  "info": [
    {
      "label": "Source IP",
      "value": "{{source_ip}}",
      "use_for_dedup": true
    },
    {
      "label": "Description",
      "value": "{{@alert.description}}",
      "use_for_dedup": false
    }
  ],
  "actions": [
    {
      "label": "View Runbook",
      "value": "https://wiki.example.com/runbook/response"
    }
  ]
}
```

## Detection severity

We use the [OCSF schema](https://schema.ocsf.io/1.1.0/classes/detection_finding) for detection severity:

* Unknown
* Information
* Low
* Medium
* High
* Critical
* Fatal
* Other

The detection severity must be one of these string values, e.g.

```json
"severity": "Critical"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.scanner.dev/scanner/using-scanner-complete-feature-reference/developer-tools/api/detection-rules.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
