Configure notification routes
Get paged when a backup fails, a restore drill cannot recover, the audit chain breaks, or the worker stops — add and test a route per channel.
For a backup product the day-two question is simple: who gets paged when something breaks? Walwarden's notification center wires each failure condition to one or more delivery channels — Slack, Discord, email, or a signed webhook — scoped to your team. This guide walks the four alert conditions, adds a route for each channel, and confirms a route fires with a test send.
Before you start
- You must be a team admin or owner. Members can view the routes but only admins and owners can add, edit, enable/disable, delete, or test them.
- For Slack and Discord, create an incoming webhook in that workspace/server first and copy its URL — you paste it into walwarden as the route destination.
- For a generic webhook, your receiver must be reachable over public HTTPS. Walwarden blocks destinations that resolve to loopback, private, link-local, or otherwise reserved addresses (SSRF protection), so a
localhostor internal-only endpoint will be rejected.
The four alert conditions
Each route is bound to exactly one event type. The notification center groups routes under these four conditions, each carrying a fixed severity:
| Condition | Severity | What it means |
|---|---|---|
| Failed backup | Warning | A backup reached failed_terminal — it exhausted its retries and did not produce an artifact. Recoverability is degraded until the next successful run. |
| Failed restore drill | Critical | A restore drill could not recover the database. The recoverability claim is unverified until the next drill succeeds. |
| Audit chain anomaly | Critical | An audit-chain integrity check found a hash mismatch. Evidence bundles are not authoritative until verified offline with @walwarden/verifier. |
| Worker not running | Critical | The walwarden worker has not reported a heartbeat for more than five minutes. Backups stop running silently until the worker is restarted. |
A condition with no active route reaches nobody. The notification center shows an "Alerts are off — setup incomplete" callout until at least one route exists, and the dashboard alerts card links here so the gap is visible.
The four channels
| Channel | Destination format |
|---|---|
| Slack | An incoming webhook URL on hooks.slack.com, e.g. https://hooks.slack.com/services/T.../B.../... |
| Discord | A webhook URL on discord.com, e.g. https://discord.com/api/webhooks/.../... |
A plain address, e.g. security@example.com | |
| Webhook | Any public HTTPS endpoint, e.g. https://relay.example.com/walwarden. Each delivery is HMAC-signed. |
Step 1: Open the notification center
In the dashboard, go to Settings → Notification routes to open the notification center. Each of the four conditions is a card. Existing routes for a condition appear in its table, with a Destination, Delivery health (last delivered, 24h failure count, last error), and State (active/disabled) column.
Step 2: Add a route
On the condition you want to wire, click + Add route. A small form appears with three fields:
- Channel — Slack, Discord, Email, or Webhook. The destination placeholder updates to match.
- Destination (required) — the webhook URL or email address, per the formats above. Walwarden validates it on submit: Slack expects a
hooks.slack.comURL, Discord adiscord.comwebhook URL, email a syntactically valid address, and a generic webhook any public HTTPS URL that passes the SSRF check. An invalid destination is rejected with a specific reason. - Label (optional) — a short human tag, e.g.
ops-channeloroncall-email, shown next to the channel name so you can tell two routes on the same condition apart.
Click Add.
Webhook signing secret (webhook routes only)
When you add a webhook route, walwarden mints a per-route signing secret and shows it exactly once. Copy it immediately — it is not retrievable later. Stamp it into your receiver's signature-verification config so it can authenticate deliveries.
Each webhook delivery carries:
X-Walwarden-Signature—v1=<hex>where<hex>is the HMAC-SHA256 of<timestamp>.<body>using the signing secret.X-Walwarden-Timestamp— the signing timestamp, so your receiver can verify the signature and enforce a clock-skew window against replay.X-Walwarden-EventandX-Walwarden-Delivery— the event type and a per-delivery id.
The JSON body uses the walwarden.notification.v1 schema:
{
"schema": "walwarden.notification.v1",
"eventType": "failed_backup",
"eventId": "...",
"severity": "warning",
"occurredAt": "2026-06-30T12:00:00.000Z",
"organizationSlug": "your-team",
"subject": "Backup failed for db_prod",
"summary": "...",
"details": {}
}Slack, Discord, and email routes do not need a secret — they post to a destination you already trust.
Step 3: Verify the route fires (test send)
Do not wait for a real failure to find out a route is misconfigured. Each route row has a Send test action. Click it to push a synthetic alert through the full delivery path — the same dispatcher, signing, and counters a real event uses.
The result is one of two outcomes:
- Delivered — the channel accepted the delivery. The route's Delivery health updates with a fresh "Last delivered" time.
- Queued (pending) — the test was enqueued and will deliver on the next worker tick. Watch the route's delivery health; "Last delivered" advances once it lands.
If the channel rejects the delivery (a bad Slack/Discord URL, a 4xx from your webhook receiver, or the per-minute send cap), the test surfaces an error banner and the route's Failures (24h) and Last error advance — a failed test is never a silent no-op.
Managing routes
- Disable / Enable — temporarily stop a route from firing without deleting it (useful while you fix a downstream receiver). Disabled routes are skipped by the dispatcher.
- Delete — remove the route. A confirmation is required. Deleting a webhook route invalidates its signing secret.
- Edit — update the destination or label on an existing route. Changing a webhook destination re-validates it against the SSRF blocklist.
Every add, edit, and delete is written to the org's audit chain (notification.route_created / route_updated / route_deleted), so route configuration is itself part of the evidence trail.
Delivery, retries, and rate limits
- Deliveries follow bounded retries — 1 minute, 5 minutes, 15 minutes, 1 hour — with a hard cap of five attempts inside a 24-hour window. A
4xx(other than 408/425/429) is treated as a permanent failure and is not retried. - Each route is capped at 60 outbound deliveries per minute, so a noisy failure loop on one route cannot self-DoS your Slack/Discord/webhook receiver.
- Walwarden honors a
Retry-After(Slack/webhook) orX-RateLimit-Reset-After(Discord) the provider returns, never posting sooner than asked, but never extending past the 24-hour budget.
Related
- What is not shipped — the honest boundary of what walwarden does today.
- Audit chain — what an audit-chain anomaly means and how to verify a bundle offline.
- Run a restore drill — the action a failed-restore-drill alert tells you to repeat.