---
title: "Routing Rules"
description: "List, create, update and delete Incident Management routing rules: which team a new incident is assigned to, and an optional severity override."
---

`GET /api/im/routing` · `POST /api/im/routing` · `GET /api/im/routing/:id` · `PATCH /api/im/routing/:id` · `DELETE /api/im/routing/:id`

A **routing rule** decides which [team](/api/incident-management/teams) a new incident belongs to. When an alert opens an incident, the rules of your organization are walked in order of `priority` (lowest first, `id` as tiebreak). The first rule whose `match` applies wins: the incident goes to that rule's `teamId`, and `severityOverride` (if set) replaces the alert's severity. If no rule matches, the incident goes to the team of the [alert source](/api/incident-management/alert-sources) that received the alert.

## Authentication

Requires the base IM access every endpoint in this API needs (an IM-eligible role `admin`, `editor` or `responder`, or an organization-wide API token; Incident Management must be enabled for the organization). Reading is open to any IM-eligible role. **Creating, updating and deleting** additionally require the write bar: your role must be `admin`, or you must be a team admin of the rule's team. An organization-wide API token runs with the role of the user who created it, so a token created by an organization admin passes this bar. Team-admin membership never applies to a token.

## The `match` object

| Field | Type | Description |
|-------|------|-------------|
| `source_ids` | integer[] | Alert source IDs. Max 500 entries. |
| `severity` | string[] | Alert severities, each one of `sev1`, `sev2`, `sev3`, `sev4`. |
| `customer_ids` | integer[] | Customer IDs. Max 500 entries. |
| `monitor_ids` | integer[] | Monitor IDs. Max 500 entries. |
| `tags` | string[] | Non-empty strings. Max 200 entries. |
| `field_matches` | object | String values only. Max 50 keys. |

An empty object `{}` (or omitting `match`) matches every alert, which makes a catch-all rule at a high `priority` number. Every ID in `source_ids`, `customer_ids` and `monitor_ids` must belong to your organization, otherwise the request fails with `422`.

<Callout type="warn">
Today the routing engine evaluates only `source_ids` and `severity`. A rule that sets any of `customer_ids`, `monitor_ids`, `tags` (non-empty) or `field_matches` (even as `{}`) is stored, but never matches an alert. Use `source_ids` and `severity` for rules that must take effect.
</Callout>

## List routing rules

`GET /api/im/routing`

Returns all rules of your organization, in evaluation order (`priority` ascending, then `id` ascending).

### Example (cURL)

```bash
curl -X GET "$BASE_URL/api/im/routing" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"
```

### Response

`200 OK`

```json
[
  {
    "id": 4,
    "organizationId": 1,
    "priority": 10,
    "match": { "source_ids": [7], "severity": ["sev1", "sev2"] },
    "teamId": 3,
    "escalationPolicyId": null,
    "severityOverride": "sev1",
    "createdAt": "2026-09-14T08:00:00.000Z",
    "updatedAt": "2026-09-14T08:00:00.000Z"
  },
  {
    "id": 5,
    "organizationId": 1,
    "priority": 100,
    "match": {},
    "teamId": 2,
    "escalationPolicyId": null,
    "severityOverride": null,
    "createdAt": "2026-09-14T08:05:00.000Z",
    "updatedAt": "2026-09-14T08:05:00.000Z"
  }
]
```

## Get a routing rule

`GET /api/im/routing/:id`

Returns one rule, same shape as a list item.

## Create a routing rule

`POST /api/im/routing`

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `teamId` | integer | Yes | Target team. Must belong to your organization. You need the write bar on this team. |
| `priority` | integer | No | Evaluation order, lower first. Non-negative integer, default `100`. |
| `match` | object | No | See [the `match` object](#the-match-object). Default `{}` (matches everything). |
| `severityOverride` | string \| null | No | `sev1` to `sev4`, or `null` (default) to keep the alert's severity. |
| `escalationPolicyId` | integer \| null | No | Legacy field. Accepted (positive integer or `null`) and stored, but has no effect. |

### Example (cURL)

```bash
curl -X POST "$BASE_URL/api/im/routing" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "teamId": 3,
    "priority": 10,
    "match": { "source_ids": [7], "severity": ["sev1", "sev2"] },
    "severityOverride": "sev1"
  }'
```

### Response

`200 OK`: the created rule (same shape as a list item).

## Update a routing rule

`PATCH /api/im/routing/:id`

Partial update. Send only the fields you want to change: `priority`, `match`, `teamId`, `severityOverride`, `escalationPolicyId` (same validation as on create). Other fields are ignored. A new `match` replaces the stored one completely. You need the write bar on the rule's current team, and, when you change `teamId`, also on the new team (which must belong to the same organization).

```bash
curl -X PATCH "$BASE_URL/api/im/routing/4" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "priority": 5 }'
```

`200 OK`: the updated rule.

## Delete a routing rule

`DELETE /api/im/routing/:id`

```bash
curl -X DELETE "$BASE_URL/api/im/routing/4" \
  -H "Authorization: Bearer $TOKEN"
```

`200 OK`

```json
{ "success": true }
```

## Common errors

- `401 Unauthorized` when not authenticated
- `403 Forbidden` (`imAccessDenied`) when using a customer-scoped token, or a session without an IM-eligible role
- `403 Forbidden` (`imNotEnabled`) when Incident Management is not enabled for the organization
- `403 Forbidden` (`imTeamWriteDenied`) when you do not meet the write bar for the rule's team (or the new team)
- `400 Bad Request` (`invalidRequestBody`) when `:id` is not a positive integer, `teamId` is missing or invalid, `priority` is not a non-negative integer, `severityOverride` is not a valid severity, `escalationPolicyId` is not a positive integer, or `match` is malformed (wrong types, too many entries)
- `404 Not Found` (`imRoutingRuleNotFound`) when the rule does not exist, or belongs to another organization
- `422 Unprocessable Entity` (`invalidTeamId`) when `teamId` does not belong to your organization
- `422 Unprocessable Entity` (`imRoutingInvalidMatchReference`) when an ID in `match` belongs to another organization or does not exist. `data.field` names the field (`source_ids`, `customer_ids` or `monitor_ids`), `data.foreignIds` lists the rejected IDs
