# 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>tags</code></td><td>list of strings</td><td>Associated tags for the detection rule. Scanner has default <a data-mention href="../../detections-and-alerting/detection-rules/mitre-tags">mitre-tags</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,
    "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,
        "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,
    "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`.                                                                                                                                           |
| `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](https://docs.scanner.dev/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/mitre-tags "mention") 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,
    "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](https://docs.scanner.dev/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-alert-formatting) 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"
```
