> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devhelm.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Alert Channels

> Configure DevHelm alert channels — Slack, PagerDuty, OpsGenie, Discord, Teams, email, webhooks, and 13 more integrations

Alert channels define the destinations for incident notifications. Each channel type has its own delivery behavior, configuration, and plan requirements.

<Tip>
  **Define this in code.** Manage alert channels as part of your monitoring-as-code workflow:
  [YAML format](/mac/yaml/alert-channels) · [Terraform](/mac/terraform/alert-channels) · [CI/CD patterns](/mac/ci-cd/overview)
</Tip>

## Channel types

All 20 channel types are available on every plan, and you can create an unlimited number of channels on any plan — there is no per-plan channel count limit.

| Type                | Configuration                      |
| ------------------- | ---------------------------------- |
| **Email**           | Recipient email addresses          |
| **Slack**           | Incoming webhook URL               |
| **Discord**         | Webhook URL                        |
| **Webhook**         | URL + optional HMAC signing secret |
| **PagerDuty**       | Events API v2 routing key          |
| **OpsGenie**        | API key                            |
| **Microsoft Teams** | Webhook URL                        |
| **Telegram**        | Bot token + chat ID                |
| **Google Chat**     | Webhook URL                        |
| **Pushover**        | User key + app token               |
| **Mattermost**      | Webhook URL                        |
| **Splunk On-Call**  | API key                            |
| **Pushbullet**      | Access token                       |
| **Linear**          | API key                            |
| **Incident.io**     | API key                            |
| **Rootly**          | API key                            |
| **Zapier**          | Webhook URL                        |
| **Datadog**         | API key                            |
| **Jira**            | API key + project key              |
| **GitLab**          | API key + project ID               |

## Lifecycle behavior

Channels fall into two notification models:

### Fire-and-forget

**Email, Slack, Discord, Teams, Webhook**

Each message is self-contained. The channel sends a notification when an incident is created and a separate notification when it's resolved. There is no state maintained in the external system.

### Trigger-resolve

**PagerDuty, OpsGenie, Splunk On-Call, Incident.io, Rootly, GitLab**

The channel opens an alert in the external system when an incident is created and explicitly resolves it when the incident resolves. The external system maintains its own state (acknowledgment, escalation, on-call routing) tied to the DevHelm incident.

This distinction matters for [escalation chain behavior](/alerting/escalation-chains#resolution-behavior) — stateful integrations always close their external alerts on resolution, even when `onResolve` is set to `silent`.

## Creating a channel

<CodeGroup>
  ```bash CLI theme={null}
  devhelm alert-channels create \
    --name "Engineering Slack" \
    --type slack \
    --webhook-url "https://hooks.slack.com/services/T.../B.../xxx"
  ```

  ```bash API theme={null}
  curl -X POST https://api.devhelm.io/api/v1/alert-channels \
    -H "Authorization: Bearer $DEVHELM_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Engineering Slack",
      "config": {
        "channelType": "slack",
        "webhookUrl": "https://hooks.slack.com/services/T.../B.../xxx"
      }
    }'
  ```
</CodeGroup>

For a generic webhook channel, pass the full `--config` JSON because the
webhook variant uses `url` (not `webhookUrl`):

```bash theme={null}
devhelm alert-channels create \
  --name "Webhook Sink" \
  --type webhook \
  --config '{"channelType":"webhook","url":"https://webhook.site/00000000-0000-0000-0000-000000000000"}'
```

Replace the `webhook.site` UUID with a fresh URL from
[webhook.site](https://webhook.site) to inspect deliveries.

### Configuration by type

<AccordionGroup>
  <Accordion title="Email">
    | Field        | Description              |
    | ------------ | ------------------------ |
    | `recipients` | Array of email addresses |
  </Accordion>

  <Accordion title="Slack">
    | Field        | Description                |
    | ------------ | -------------------------- |
    | `webhookUrl` | Slack incoming webhook URL |

    See [Slack integration](/integrations/slack) for setup instructions.
  </Accordion>

  <Accordion title="Discord">
    | Field        | Description         |
    | ------------ | ------------------- |
    | `webhookUrl` | Discord webhook URL |

    See [Discord integration](/integrations/discord) for setup instructions.
  </Accordion>

  <Accordion title="Webhook">
    | Field           | Description                                                  |
    | --------------- | ------------------------------------------------------------ |
    | `url`           | Target URL that receives POST payloads                       |
    | `signingSecret` | Optional HMAC-SHA256 signing secret for payload verification |

    See [Webhooks integration](/integrations/webhooks) for payload format and verification.
  </Accordion>

  <Accordion title="PagerDuty">
    | Field        | Description                         |
    | ------------ | ----------------------------------- |
    | `routingKey` | PagerDuty Events API v2 routing key |

    See [PagerDuty integration](/integrations/pagerduty) for setup instructions.
  </Accordion>

  <Accordion title="OpsGenie">
    | Field    | Description      |
    | -------- | ---------------- |
    | `apiKey` | OpsGenie API key |

    See [OpsGenie integration](/integrations/opsgenie) for setup instructions.
  </Accordion>

  <Accordion title="Microsoft Teams">
    | Field        | Description                |
    | ------------ | -------------------------- |
    | `webhookUrl` | Teams incoming webhook URL |

    See [Teams integration](/integrations/teams) for setup instructions.
  </Accordion>
</AccordionGroup>

## Testing a channel

Verify your configuration before using it in a notification policy:

<CodeGroup>
  ```bash CLI theme={null}
  devhelm alert-channels test <channel-id>
  ```

  ```bash API theme={null}
  curl -X POST https://api.devhelm.io/api/v1/alert-channels/test \
    -H "Authorization: Bearer $DEVHELM_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Test Slack",
      "config": {
        "channelType": "slack",
        "webhookUrl": "https://hooks.slack.com/services/T.../B.../xxx"
      }
    }'
  ```
</CodeGroup>

The CLI tests an existing channel by ID. The REST endpoint at
`/api/v1/alert-channels/test` accepts an inline config and verifies it
without persisting — useful for pre-flight validation before a `create`.

The test endpoint sends a sample notification and reports whether delivery succeeded.

## Delivery history

Track delivery attempts and failures for a channel:

```bash theme={null}
curl https://api.devhelm.io/api/v1/alert-channels/<channel-id>/deliveries \
  -H "Authorization: Bearer $DEVHELM_API_TOKEN"
```

Each delivery record includes the timestamp, target incident, HTTP status, and any error message.

## Channel fields

| Field                | Type     | Description                                            |
| -------------------- | -------- | ------------------------------------------------------ |
| `id`                 | UUID     | Unique channel identifier                              |
| `name`               | string   | Human-readable name                                    |
| `channelType`        | string   | Integration type                                       |
| `displayConfig`      | object   | Non-sensitive configuration metadata                   |
| `configHash`         | string   | SHA-256 hash of the full config (for change detection) |
| `lastDeliveryAt`     | datetime | Most recent delivery attempt                           |
| `lastDeliveryStatus` | string   | Result of the last delivery (e.g., SUCCESS, FAILED)    |

<Note>
  Channel configurations are write-only for security. After creation, the API returns `displayConfig` (non-sensitive metadata) and `configHash` but never the full secret values.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Notification policies" icon="filter" href="/alerting/notification-policies">
    Route incidents to the right channels based on rules.
  </Card>

  <Card title="Integrations" icon="puzzle-piece" href="/integrations/slack">
    Step-by-step setup for each integration.
  </Card>

  <Card title="Alerting guide" icon="wrench" href="/guides/alerting">
    End-to-end guide for setting up alerting.
  </Card>
</CardGroup>
