Channels
Supported notification channels (Slack, Discord, Teams, Telegram, email, SMS, push, PagerDuty, Opsgenie, webhooks, SSE), their configuration, message length limits, and priority mapping.
Channels are the destinations where Alphorn delivers notifications. Each channel connects to an external service - a Slack workspace, an email address, a push notification service, etc.
Supported Channels
Chat & Messaging
| Channel | Configuration |
|---|---|
| Slack | Incoming Webhook URL |
| Discord | Webhook URL |
| Microsoft Teams | Incoming Webhook URL |
| Telegram | Bot token + chat ID |
| Google Chat | Webhook URL |
| Matrix | Homeserver URL + access token + room ID |
| Mattermost | Incoming Webhook URL |
| Rocket.Chat | Incoming Webhook URL |
| Zulip | Server URL + bot email + API key + stream + topic |
| Channel | Configuration |
|---|---|
| Email (SMTP) | SMTP host, port, encryption, username, password, from address, to address |
| SendGrid | API key + from email (+ optional from name) + to email |
| Mailgun | API key + domain + region (US/EU) + from address + to address |
Push Notifications
| Channel | Configuration |
|---|---|
| Ntfy | Server URL + topic (+ optional access token) |
| Pushover | API token + user key |
| Gotify | Server URL + app token |
SMS
| Channel | Configuration |
|---|---|
| Twilio SMS | Account SID + auth token + from number + to number |
| Vonage SMS | API key + API secret + from + to number |
Incident Management
| Channel | Configuration |
|---|---|
| PagerDuty | Routing key (Events API v2 integration key) + default severity |
| Opsgenie | API key + region (US/EU) + default priority |
Custom Integrations
| Channel | Configuration |
|---|---|
| Webhook | Any HTTP endpoint URL, method, custom headers |
| Live Stream (SSE) | Output format (JSON/text) + which fields to include. See Streaming |
Adding a Channel
- Navigate to Channels in the dashboard
- Click Add channel
- Select the channel type
- Enter the required configuration - each channel type shows a setup guide in the form
- Send a test notification to verify (admins and owners; not available for Live Stream)
- Link the channel to a webhook - on the webhook page, select it in the channel list
A channel only receives notifications from webhooks it is linked to. You can link one channel to many webhooks, each with its own filter.
Channel URLs (webhook URLs, server URLs, homeserver URLs) can't point at the Alphorn instance itself. This prevents notification loops. Discord channels only accept Discord webhook URLs (https://discord.com/api/webhooks/...).
Disabling and Deleting Channels
- A disabled channel receives no new notifications, and pending retries for it are dropped. It still counts toward your plan's channel limit.
- Deleting a channel removes it from all webhooks. Its delivery history stays visible under Messages, and it no longer counts toward your plan's channel limit.
Send Rate Limits
To stay within the services' own limits, Alphorn sends at most 60 messages per minute to a Slack channel, 50 to a Discord channel, and 20 to a Telegram channel. Extra deliveries wait for the next minute without using up a retry - see Retries → Per-Channel Throttling.
Message Length Limits
Incoming titles are cut to 200 characters and messages to 4,000 characters. Some services have lower limits, so Alphorn shortens the text to fit each one before sending (longer text ends with …):
| Channel | Limit |
|---|---|
| Slack | Title 150, message 3,000 |
| Discord | Title 256, message 4,096 |
| Telegram | Title 256, title + message 4,096 |
| Google Chat | Message 4,096 |
| Pushover | Title 250, message 1,024 |
| PagerDuty | Summary 1,024 |
| Opsgenie | Message (title) 130, description 15,000 |
| Twilio SMS | 1,600 |
Email and Opsgenie need a subject or title line: they use the notification title, or the first line of the message (up to 100 characters) when there is no title. PagerDuty gets Title: message as its summary, cut to 1,024 characters.
Priority Mapping
Channels with their own priority or severity levels get the notification priority mapped onto their scale:
| Alphorn priority | ntfy | Gotify | Pushover | PagerDuty | Opsgenie |
|---|---|---|---|---|---|
| 1 (Min) | min | 1 | -1 | info | P5 |
| 2 (Low) | low | 3 | -1 | info | P4 |
| 3 (Default) | default | 5 | 0 | warning | P3 |
| 4 (High) | high | 8 | 1 | error | P2 |
| 5 (Urgent) | urgent | 10 | 2 | critical | P1 |
Notifications without a priority use the channel's default: default for ntfy, 5 for Gotify, 0 for Pushover, and the Default Severity / Default Priority you configured for PagerDuty and Opsgenie.
Channel Limits
Channel availability depends on your plan:
| Plan | Channels |
|---|---|
| Free | 3 channels |
| Pro | Unlimited |
| Business | Unlimited |
Generic Webhook
The Webhook channel lets you send notifications to any HTTP endpoint. Use it to integrate with services that Alphorn doesn't have a dedicated channel for.
| Setting | Description |
|---|---|
| Endpoint URL | Where to send the request |
| HTTP Method | POST (default) or PUT |
| Custom Headers | Extra headers, e.g. Authorization for the receiving service. Invalid header names or values are rejected when you save |
Alphorn sends a JSON body:
{
"title": "Notification title",
"message": "Notification body",
"priority": 3,
"tags": ["tag1", "tag2"],
"payload": { "the": "original JSON request body" },
"timestamp": "2025-01-15T10:30:00.000Z"
}messageandtimestampare always presenttitle,priority, andtagsare left out when the notification doesn't have thempayloadis the original JSON request body that came into the Alphorn webhook, nested under its own key. For plain-text notifications it is an empty object ({})- The test button sends a different body -
{"title", "body", "timestamp", "_test": true}- so your receiver can tell test pings apart
The request also carries a signed X-Alphorn-Trace header (other URL-based channels like Slack, Teams, Matrix, or ntfy send it too). Alphorn uses it to detect loops when a channel points at another Alphorn webhook; after 3 hops (WEBHOOK_MAX_HOPS when self-hosting), or when the notification comes back to a webhook it already passed, the request is rejected with 508. The header is signed with BETTER_AUTH_SECRET, so loops across two self-hosted instances are only detected when both use the same secret.
A Webhook channel can't point at the same Alphorn instance it runs on. To forward notifications between your own webhooks, link the channels directly to the webhook instead.
Webhooks
Receive notifications via HTTP webhooks - create a webhook, authenticate with an API key, and send JSON, Slack-compatible, or plain-text payloads.
Filtering Rules
Filter and route notifications per webhook and channel by priority, tags, title, message, or JSON payload fields - operators, AND/OR groups, regex, and testing filters.