---
title: "Personal Notification Settings"
description: "How Incident Management reaches you: channels, notification rules per urgency, channels per severity, phone verification, test notifications and your notification log."
---

`GET /api/im/notification-settings` · `PATCH /api/im/notification-settings` · `PUT /api/im/notification-settings/channels` · `PUT /api/im/notification-settings/severity` · `POST /api/im/notification-settings/rules` · `DELETE /api/im/notification-settings/rules/:id` · `POST /api/im/notification-settings/verify-phone` · `POST /api/im/notification-settings/verify-phone-confirm` · `POST /api/im/notification-settings/test` · `GET /api/im/notification-settings/logs`

When an escalation pages you, these settings decide **how** you are reached. They belong to you alone: every endpoint reads and writes the settings of the calling user, there is no way to change someone else's. Your settings are created on first access.

## Concepts

- **Channels**: `push` (mobile app), `sms`, `voice` and `email`.
- **Rules** form your personal notification chain per **urgency** (`high` or `low`): "after `delayMinutes`, notify me via `channel`". A delay of `0` notifies immediately; delays run from 0 to 1440 minutes. The same urgency/delay/channel combination exists at most once.
- **Severity filter** (`severityChannels`): per incident severity (`sev1` to `sev4`), which channels may be used. It is stored sparse: a severity or channel that is not listed is **allowed**. `{"sev4": {"sms": false, "voice": false}}` keeps low-severity incidents off your phone and changes nothing else.
- **Phone**: `sms` and `voice` need a verified phone number in E.164 format (`+` followed by 7 to 15 digits, e.g. `+491701234567`). Changing the number resets the verification.

## Authentication

Any IM-eligible role (`admin`, `editor`, `responder`) with a **user session**. Incident Management must be enabled for the organization. Personal settings belong to a person: an organization-wide API token receives `403` (`imAccessDenied`), the log endpoint `403` (`imUserSessionRequired`).

## Get your settings

`GET /api/im/notification-settings`

### Example (cURL)

```bash
curl -X GET "$BASE_URL/api/im/notification-settings" \
  -b "$SESSION_COOKIE" \
  -H "Accept: application/json"
```

### Response

```json
{
  "id": 31,
  "phoneNumber": "+491701234567",
  "phoneVerified": true,
  "channels": { "push": true, "sms": true, "email": true },
  "severityChannels": { "sev4": { "sms": false, "voice": false } },
  "rules": [
    { "id": 201, "urgency": "high", "delayMinutes": 0, "channel": "push" },
    { "id": 202, "urgency": "high", "delayMinutes": 5, "channel": "sms" },
    { "id": 203, "urgency": "low", "delayMinutes": 0, "channel": "email" }
  ]
}
```

`rules` are sorted by urgency, then delay.

## Change phone number or channel switches

`PATCH /api/im/notification-settings`

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `phoneNumber` | string or null | No | E.164 number, or `null` to remove it. A new number is unverified until confirmed, and any pending verification code is discarded. Existing `sms`/`voice` rules stay, but are skipped while the number is unverified. |
| `channels` | object | No | Channel switches (`push`, `sms`, `voice`, `email` → boolean), merged into the stored ones. |

### Example (cURL)

```bash
curl -X PATCH "$BASE_URL/api/im/notification-settings" \
  -b "$SESSION_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber":"+491701234567"}'
```

### Response

```json
{
  "id": 31,
  "phoneNumber": "+491701234567",
  "phoneVerified": false,
  "channels": { "push": true, "email": true }
}
```

## Set channels in one step

`PUT /api/im/notification-settings/channels`

The simple form of the rule chain: per channel, on or off with one delay, applied to **both** urgencies. For every channel named in the request, its existing rules are replaced; channels not named stay as they are.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `channels` | object | Yes | At least one of `push`, `sms`, `voice`, `email`, each `{ "enabled": boolean, "delayMinutes": 0..1440 }`. |

### Example (cURL)

```bash
curl -X PUT "$BASE_URL/api/im/notification-settings/channels" \
  -b "$SESSION_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{"channels":{"push":{"enabled":true,"delayMinutes":0},"sms":{"enabled":true,"delayMinutes":5}}}'
```

### Response

```json
{
  "channels": { "push": true, "sms": true },
  "rules": [
    { "id": 210, "urgency": "high", "delayMinutes": 0, "channel": "push" },
    { "id": 211, "urgency": "high", "delayMinutes": 5, "channel": "sms" },
    { "id": 212, "urgency": "low", "delayMinutes": 0, "channel": "push" },
    { "id": 213, "urgency": "low", "delayMinutes": 5, "channel": "sms" }
  ]
}
```

## Set the severity filter

`PUT /api/im/notification-settings/severity`

Replaces the stored filter as a whole.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `severityChannels` | object | Yes | Keys `sev1` to `sev4`, each an object of `push`/`sms`/`voice`/`email` → boolean. Unlisted severities and channels are allowed. `{}` allows everything. |

### Example (cURL)

```bash
curl -X PUT "$BASE_URL/api/im/notification-settings/severity" \
  -b "$SESSION_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{"severityChannels":{"sev4":{"sms":false,"voice":false}}}'
```

### Response

```json
{
  "severityChannels": { "sev4": { "sms": false, "voice": false } }
}
```

## Add a rule

`POST /api/im/notification-settings/rules`

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `urgency` | string | Yes | `high` or `low`. |
| `delayMinutes` | integer | Yes | 0 to 1440. |
| `channel` | string | Yes | `push`, `sms`, `voice` or `email`. `sms` and `voice` need a verified phone number. |

### Example (cURL)

```bash
curl -X POST "$BASE_URL/api/im/notification-settings/rules" \
  -b "$SESSION_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{"urgency":"high","delayMinutes":10,"channel":"voice"}'
```

### Response

```json
{ "id": 214, "urgency": "high", "delayMinutes": 10, "channel": "voice" }
```

## Delete a rule

`DELETE /api/im/notification-settings/rules/:id`

Deletes one of **your** rules. Returns `{ "success": true }`.

## Verify your phone number

`POST /api/im/notification-settings/verify-phone` sends a 6-digit code by SMS to the stored number. The code is valid for 10 minutes and allows 5 attempts. At most 3 codes per hour can be requested.

```json
{ "sent": true }
```

`POST /api/im/notification-settings/verify-phone-confirm` confirms it:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `code` | string | Yes | The 6-digit code. |

```bash
curl -X POST "$BASE_URL/api/im/notification-settings/verify-phone-confirm" \
  -b "$SESSION_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{"code":"482913"}'
```

```json
{ "phoneVerified": true }
```

## Send a test notification

`POST /api/im/notification-settings/test`

Sends a test message on each channel, as a `sev1` incident would reach you after your severity filter. No incident is created. At most 5 per hour, shared with the [setup test page](/api/incident-management/setup#send-a-test-page).

```json
{
  "results": [
    { "channel": "email", "ok": true },
    { "channel": "sms", "ok": false, "error": "phone_not_verified" },
    { "channel": "push", "ok": true },
    { "channel": "voice", "ok": false, "error": "not_available_yet" }
  ]
}
```

`error` values: `disabled_by_settings` (filtered out by your severity filter), `phone_not_verified`, `no_email_on_account`, `not_available_yet` (voice has no test yet), or the provider's error message.

## Your notification log

`GET /api/im/notification-settings/logs`

Every notification Incident Management scheduled, sent, skipped, cancelled or failed for **you**, newest first.

### Query parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `limit` | integer | No | 1 to 100, default 50. |
| `before` | integer | No | Return entries older than this entry id; use `nextBefore` of the previous page. |

### Response

```json
{
  "entries": [
    {
      "id": 99812,
      "at": "2026-10-10T07:12:03.000Z",
      "kind": "notification_sent",
      "channel": "sms",
      "reason": null,
      "error": null,
      "provider": "seven",
      "tier": 1,
      "repeat": 0,
      "delayMinutes": 5,
      "urgency": "high",
      "incident": { "id": "1834", "title": "API 5xx rate above 5 %", "severity": "sev2", "status": "acknowledged" }
    }
  ],
  "hasMore": true,
  "nextBefore": 99812
}
```

`kind` is one of `notification_scheduled`, `notification_sent`, `notification_failed`, `notification_cancelled`, `notification_skipped`; `reason` and `error` explain skips and failures.

## Common errors

- `400 Bad Request` (`invalidRequestBody`) for an invalid body or query: unknown channel or urgency, delay outside 0 to 1440, malformed `severityChannels`, a code that is not 6 digits, `limit`/`before` out of range
- `400 Bad Request` (`invalidPhoneNumber`) when `phoneNumber` is not in E.164 format
- `401 Unauthorized` when not authenticated
- `403 Forbidden` (`imAccessDenied`) when the caller has no IM-eligible role, or calls with an organization-wide API token
- `403 Forbidden` (`imUserSessionRequired`) when reading the log with an organization-wide API token
- `403 Forbidden` (`imNotEnabled`) when Incident Management is not enabled for the organization
- `404 Not Found` (`imNotificationRuleNotFound`) when the rule does not exist or is not yours
- `409 Conflict` (`imNotificationRuleExists`) when the same urgency/delay/channel rule already exists
- `422 Unprocessable Entity` (`imPhoneNotVerified`) when enabling `sms`/`voice` without a verified number
- `422 Unprocessable Entity` (`imPhoneNotSet`) when requesting a code without a stored number
- `422 Unprocessable Entity` (`imPhoneVerifyCodeInvalid`, `imPhoneVerifyCodeExpired`, `imPhoneVerifyTooManyAttempts`) when the code is wrong, older than 10 minutes, or tried too often
- `429 Too Many Requests` (`imPhoneVerifyRateLimited`) after 3 codes in an hour; (`imTestNotificationRateLimited`) after 5 test notifications in an hour. Both carry `retryAfterSeconds`.
- `502 Bad Gateway` (`imPhoneVerifySendFailed`) when the SMS provider rejected the code message
