walwarden
GuidesNotifications

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 localhost or 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:

ConditionSeverityWhat it means
Failed backupWarningA backup reached failed_terminal — it exhausted its retries and did not produce an artifact. Recoverability is degraded until the next successful run.
Failed restore drillCriticalA restore drill could not recover the database. The recoverability claim is unverified until the next drill succeeds.
Audit chain anomalyCriticalAn audit-chain integrity check found a hash mismatch. Evidence bundles are not authoritative until verified offline with @walwarden/verifier.
Worker not runningCriticalThe 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

ChannelDestination format
SlackAn incoming webhook URL on hooks.slack.com, e.g. https://hooks.slack.com/services/T.../B.../...
DiscordA webhook URL on discord.com, e.g. https://discord.com/api/webhooks/.../...
EmailA plain address, e.g. security@example.com
WebhookAny 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.com URL, Discord a discord.com webhook 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-channel or oncall-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-Signaturev1=<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-Event and X-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) or X-RateLimit-Reset-After (Discord) the provider returns, never posting sooner than asked, but never extending past the 24-hour budget.
  • 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.