---
title: "Escalation Tiers"
description: "Read and edit a team's escalation chain: ordered tiers, their auto-escalation and repeat settings, and the schedules under each tier."
---

A team's escalation chain is an ordered list of **tiers**. Tier 1 is paged first; the people on call in a tier are whoever the tier's schedules have on shift right now. Each tier decides whether and when the incident moves on to the next tier, and how often the tier is paged again first. Whole-chain repeats live on the team ([Update a team](/api/incident-management/teams#update-a-team)).

## Authentication

Base IM access: an IM-eligible role or an organization-wide API token, and Incident Management activated for the organization. Reading the chain is open to any caller with that access. Every write needs the team write bar: organization `admin` role, or team admin of this team. An API token runs with the role of the user who created it, so only a token created by an organization admin passes.

## Tier fields

| Field | Type | Description |
|-------|------|-------------|
| `tierOrder` | integer | Position in the chain, 1 = paged first. Changed only through [Reorder](#reorder-tiers). |
| `autoEscalationEnabled` | boolean | Whether the incident moves on to the next tier automatically. Default `true`. |
| `autoEscalationAfterMinutes` | integer | Minutes before it moves on, `0` or more. Default `5`. |
| `autoEscalationStopMode` | string | `acknowledged` or `resolved`: the incident state that stops the escalation. Default `acknowledged`. |
| `autoEscalationSeverities` | array \| null | Severities that escalate automatically: a subset of `critical`, `warning`, `minor`. `null` = all. |
| `autoEscalationTimeFilters` | array | Weekly windows in which auto-escalation may fire, up to 50, each `{ from: "HH:mm", until: "HH:mm", days: number[] }` with ISO weekdays (1 = Monday). `until` may be `"24:00"`. `[]` = always. |
| `repeats` | integer | How many more times this tier is paged before moving on, `0` or more. Default `0`. |
| `repeatsAfterMinutes` | integer \| null | Minutes between those repeats. `null` = use `autoEscalationAfterMinutes`. |
| `repeatsStopMode` | string | `acknowledged` or `resolved`: the incident state that stops the repeats. Default `acknowledged`. |

## Read the escalation chain

`GET /api/im/teams/:id/escalations`

Returns all tiers in order, each with its schedules, rotation groups and members, plus the team's escalation settings.

### Example (cURL)

```bash
curl -X GET "$BASE_URL/api/im/teams/3/escalations" \
  -H "Authorization: Bearer $TOKEN"
```

### Response

`200 OK`

```json
{
  "tiers": [
    {
      "id": 21,
      "tierOrder": 1,
      "autoEscalationEnabled": true,
      "autoEscalationAfterMinutes": 5,
      "autoEscalationStopMode": "acknowledged",
      "autoEscalationSeverities": null,
      "autoEscalationTimeFilters": [],
      "repeats": 0,
      "repeatsAfterMinutes": null,
      "repeatsStopMode": "acknowledged",
      "schedules": [
        {
          "id": 7,
          "displayName": "Primary On-Call",
          "timezone": "Europe/Berlin",
          "effectiveFrom": null,
          "effectiveUntil": null,
          "weeklySchedules": [],
          "rotationMode": "explicit",
          "rotationRepeats": "weekly",
          "customRepeatUnit": null,
          "customRepeatValue": null,
          "autoRotationSize": null,
          "roundRobinSize": 1,
          "startsOnDayOfWeek": 1,
          "startsOnDateOfMonth": null,
          "startsOnTime": "09:00",
          "rotations": [
            {
              "id": 12,
              "rotationOrder": 1,
              "members": [
                { "userId": "u_abc123", "userName": "Ada Lovelace", "userImage": null, "memberOrder": 1 }
              ]
            }
          ]
        }
      ]
    }
  ],
  "teamSettings": {
    "timezone": "Europe/Berlin",
    "escalationRepeats": 1,
    "escalationRepeatsAfterMinutes": 15,
    "escalationRepeatsStopMode": "acknowledged",
    "engagementReportEnabled": false,
    "engagementReportDayOfWeek": null,
    "engagementReportTime": null
  }
}
```

The schedule fields are explained under [Rotation cadence](/api/incident-management/schedules#rotation-cadence) and [Update a schedule](/api/incident-management/update-schedule).

## Add a tier

`POST /api/im/teams/:id/tiers`

Appends a tier at the end of the chain (`tierOrder` = highest + 1) with the default settings from the table above. In the same step it creates one schedule under the tier: named `Tier N schedule`, 24/7, `rotationMode: "none"`, in the team's timezone (or `UTC` if the team has none), with one rotation group holding the given members in the given order.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `memberUserIds` | string[] | Yes | 1 to 200 distinct user ids, all members of this team. |

### Example (cURL)

```bash
curl -X POST "$BASE_URL/api/im/teams/3/tiers" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "memberUserIds": ["u_abc123", "u_def456"] }'
```

### Response

`200 OK`: the tier fields plus `schedules`, holding the one new schedule in the same shape as in the escalation chain (members without `userImage`).

```json
{
  "id": 22,
  "tierOrder": 2,
  "autoEscalationEnabled": true,
  "autoEscalationAfterMinutes": 5,
  "autoEscalationStopMode": "acknowledged",
  "autoEscalationSeverities": null,
  "autoEscalationTimeFilters": [],
  "repeats": 0,
  "repeatsAfterMinutes": null,
  "repeatsStopMode": "acknowledged",
  "schedules": [
    {
      "id": 8,
      "displayName": "Tier 2 schedule",
      "timezone": "Europe/Berlin",
      "effectiveFrom": null,
      "effectiveUntil": null,
      "weeklySchedules": [],
      "rotationMode": "none",
      "rotationRepeats": null,
      "customRepeatUnit": null,
      "customRepeatValue": null,
      "autoRotationSize": null,
      "roundRobinSize": 1,
      "startsOnDayOfWeek": null,
      "startsOnDateOfMonth": null,
      "startsOnTime": null,
      "rotations": [
        {
          "id": 14,
          "rotationOrder": 1,
          "members": [
            { "userId": "u_abc123", "userName": "Ada Lovelace", "memberOrder": 1 },
            { "userId": "u_def456", "userName": "Bob Fixit", "memberOrder": 2 }
          ]
        }
      ]
    }
  ]
}
```

## Update a tier

`PATCH /api/im/teams/:id/tiers/:tierId`

Every field from the [tier fields](#tier-fields) table except `tierOrder` is optional and patchable. Only fields present in the body change.

### Example (cURL)

```bash
curl -X PATCH "$BASE_URL/api/im/teams/3/tiers/21" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "autoEscalationAfterMinutes": 10,
    "autoEscalationSeverities": ["critical"],
    "autoEscalationTimeFilters": [{ "from": "18:00", "until": "08:00", "days": [1, 2, 3, 4, 5] }]
  }'
```

### Response

`200 OK`: the tier fields after the update (without `schedules`).

## Delete a tier

`DELETE /api/im/teams/:id/tiers/:tierId`

Deletes the tier together with its schedules, rotation groups and shifts. The remaining tiers keep their `tierOrder`, so deleting tier 2 of 3 leaves orders 1 and 3. Close the gap with [Reorder](#reorder-tiers) if you need contiguous numbers.

### Example (cURL)

```bash
curl -X DELETE "$BASE_URL/api/im/teams/3/tiers/22" \
  -H "Authorization: Bearer $TOKEN"
```

### Response

`200 OK`

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

## Reorder tiers

`POST /api/im/teams/:id/tiers/reorder`

Renumbers the chain to `1..n` in the order you send.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `tierIds` | number[] | Yes | Every tier id of this team exactly once, in the new order. |

### Example (cURL)

```bash
curl -X POST "$BASE_URL/api/im/teams/3/tiers/reorder" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "tierIds": [22, 21] }'
```

### Response

`200 OK`

```json
{ "tiers": [{ "id": 22, "tierOrder": 1 }, { "id": 21, "tierOrder": 2 }] }
```

## Add a schedule to a tier

`POST /api/im/teams/:id/tiers/:tierId/schedules`

Creates a further schedule under a tier, for example a follow-the-sun schedule in another timezone, with its cadence and rotation groups in one call. The tier's on-call set is the union of what all its schedules have on shift.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | 1 to 120 characters after trimming. |
| `timezone` | string | Yes | IANA zone the schedule is evaluated in. |
| `effectiveFrom` | string \| null | No | ISO timestamp before which the schedule pages nobody. |
| `effectiveUntil` | string \| null | No | ISO timestamp after which the schedule pages nobody. |
| `weeklySchedules` | array | No | On-call windows, same shape as `autoEscalationTimeFilters`. Omitted or `[]` = 24/7. |
| `rotations` | array | No | Rotation groups, up to 50, each `{ members: string[] }` with up to 200 distinct members of this team. Array order is rotation order. |

Plus the cadence fields from [Rotation cadence](/api/incident-management/schedules#rotation-cadence). Omitted cadence fields default to `rotationMode: "none"`, `roundRobinSize: 1`, everything else `null`. The resulting cadence is validated as a whole.

### Example (cURL)

```bash
curl -X POST "$BASE_URL/api/im/teams/3/tiers/21/schedules" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "APAC Follow-the-Sun",
    "timezone": "Asia/Singapore",
    "weeklySchedules": [{ "from": "09:00", "until": "18:00", "days": [1, 2, 3, 4, 5] }],
    "rotationMode": "explicit",
    "rotationRepeats": "weekly",
    "startsOnDayOfWeek": 1,
    "startsOnTime": "09:00",
    "rotations": [{ "members": ["u_abc123"] }, { "members": ["u_def456"] }]
  }'
```

### Response

`200 OK`: the new schedule in the same shape as in the escalation chain (members without `userImage`).

## Common errors

- `401 Unauthorized` (`unauthorized`) when not authenticated
- `403 Forbidden` (`imAccessDenied`) for a customer-scoped token, or a session without an IM-eligible role
- `403 Forbidden` (`imNotEnabled`) when Incident Management is not activated for the organization
- `403 Forbidden` (`imTeamWriteDenied`) on any write when you are neither organization admin nor team admin of this team
- `404 Not Found` (`imTeamNotFound`) when the team does not exist or belongs to another organization
- `404 Not Found` (`imEscalationTierNotFound`) when `:tierId` is not a tier of this team
- `404 Not Found` (`imTeamMemberNotFound`) when a user id in `memberUserIds` or `rotations` is not a member of this team
- `400 Bad Request` (`invalidRequestBody`) when a path id is not a positive integer, `memberUserIds` is missing, empty or holds an empty id, `tierIds` is missing, empty, or not distinct positive integers, `name` or `timezone` is missing or invalid, `effectiveFrom`/`effectiveUntil` is not a valid timestamp, or `rotations` is malformed
- `422 Unprocessable Entity` (`imTierReorderMismatch`) when `tierIds` is not exactly this team's set of tier ids
- `422 Unprocessable Entity` (`imInvalidRequestBody`) when `autoEscalationEnabled` is not a boolean
- `422 Unprocessable Entity` (`imInvalidNumber`) when `autoEscalationAfterMinutes`, `repeats` or `repeatsAfterMinutes` is not an integer of `0` or more, or a cadence number is not an integer of `1` or more
- `422 Unprocessable Entity` (`imInvalidStopMode`) when a stop mode is not `acknowledged` or `resolved`
- `422 Unprocessable Entity` (`imInvalidSeverities`) when `autoEscalationSeverities` is neither `null` nor a list of `critical`, `warning`, `minor`
- `422 Unprocessable Entity` (`imInvalidTimeFilter`) when a window list is not an array, has more than 50 entries, or an entry is not an object or has no `days` array
- `422 Unprocessable Entity` (`imInvalidTimeOfDay`) when a window's `from`/`until` or `startsOnTime` is not `"HH:mm"`
- `422 Unprocessable Entity` (`imInvalidDayOfWeek`) when a window day or `startsOnDayOfWeek` is not 1 to 7
- `422 Unprocessable Entity` (`imInvalidRotationMode`) when `rotationMode` is not `none`, `auto` or `explicit`
- `422 Unprocessable Entity` (`imInvalidRotation`) when the cadence does not hold together, a list exceeds 200 members or 50 rotation groups, or a user id appears twice in one list
- `409 Conflict` (`imTierOrderConflict`) when two tiers were added at the same moment; retry
