---
title: "Notification Channels"
description: "Manage how and where alerts are delivered. Channels can be organization-level (default for all customers), customer-level (override for a specific customer), or website-level (override for a specific monitor)."
---

## Authentication

All examples assume a bearer token:

```bash
BASE_URL="https://uptimeify.io"
TOKEN="<your-api-token>"
```

## Channel Types and Config

Each channel type has a specific `config` structure:

| Type | Config Fields | Notes |
|------|--------------|-------|
| `email` | `{ email, to }` | Email address and recipient name |
| `sms` | `{ phoneNumber }` | Phone number in international format |
| `webhook` | `{ url, method?, headers?, bodyTemplate?, timeout?, retryAttempts?, retryDelay?, expectedStatusCodes?, secret? }` | HTTP webhook. `secret` for HMAC signing |
| `slack` | `{ secret }` | Slack incoming webhook URL |
| `discord` | `{ secret }` | Discord incoming webhook URL |
| `pagerduty` | `{ routingKey }` | PagerDuty Events API v2 routing key |
| `pushover` | `{ userKey, apiToken }` | Pushover user key and API token |
| `opsgenie` | `{ apiKey }` | Opsgenie API key |

Secrets (webhook `secret`, Slack/Discord URLs, PagerDuty routing keys, Pushover credentials, Opsgenie API keys) are **encrypted at rest** and **redacted in API responses** (replaced with `null`, with `hasSecret: true` flags).

## Webhook Signature Verification

When a `secret` is configured on a webhook channel, Uptimeify signs outgoing payloads so receivers can verify authenticity.

**Algorithm:** HMAC-SHA256

**Header:** `X-Webhook-Signature`: hex-encoded HMAC-SHA256 digest

**Companion headers sent with every webhook:**

| Header | Value |
|--------|-------|
| `X-Webhook-Signature` | Hex-encoded HMAC-SHA256 digest |
| `X-Webhook-Signature-Algorithm` | `sha256` |
| `X-Webhook-Timestamp` | ISO 8601 timestamp (e.g. `2026-05-05T12:00:00.000Z`) |
| `X-Webhook-Attempt` | 1-based retry number (e.g. `1`, `2`, `3`) |
| `X-Webhook-Event` | Event type: `alert`, `recovery`, or `dnsbl` |

**Verification steps:**

1. Read the raw request body as a string (do not parse as JSON first).
2. Compute HMAC-SHA256 using the `secret` you configured in the channel as the key and the raw body string as the message.
3. Compare the result (hex-encoded) with the value of the `X-Webhook-Signature` header using a constant-time comparison.
4. Optionally check `X-Webhook-Timestamp` for replay protection.

```javascript
// Node.js verification example
const crypto = require('crypto')

function verifySignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  )
}
```

```python
# Python verification example
import hmac, hashlib

def verify_signature(raw_body, signature, secret):
    expected = hmac.new(
        secret.encode('utf-8'),
        raw_body.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)
```

## Scope Resolution

When listing channels, the scope determines which channels are returned:

- **Organization-level** (`organizationId` only, no `customerId`/`websiteId`): Default channels for all customers
- **Customer-level** (`customerId` set, no `websiteId`): Customer-specific overrides
- **Website-level** (`websiteId` set): Per-monitor overrides

## Endpoints

- [List Notification Channels](./list-notification-channels)
- [Create Notification Channel](./create-notification-channel)
- [Update Notification Channel](./update-notification-channel)
- [Delete Notification Channel](./delete-notification-channel)
- [Test Notification Channel](./test-notification-channel)

