API

Notifications API

Manage delivery channels, per-event subscriptions, org defaults, and the in-app alert feed.

The Notifications API decides who hears about events like a failed deploy or an expiring SSL cert, and how. You register channels (where alerts go — email, webhook, Slack, or the in-app bell), toggle subscriptions (which event categories reach each channel), set org-wide defaults for new members, and read deliveries (the alert feed behind the bell icon). In the dashboard this is the Settings → Notifications page. Channels, subscriptions, and deliveries are per-user; defaults are per-org.

Base path & auth

All paths are relative to your instance, under /api — e.g. https://your-host/api/notifications/channels. Send a personal access token as a bearer header (Authorization: Bearer <token>), created with alaf server token create. The dashboard uses your session cookie instead. See the API overview and the auth model for details.

Available on every instance

This module ships on both self-hosted and cloud instances. There is no dedicated alaf server CLI command — manage notifications from the dashboard or these endpoints directly.

Endpoints

Method & pathPermissionWhat it does
GET /api/notifications/categoriesnotifications:readList notification categories (the registry of event types).
GET /api/notifications/channelsnotifications:readList the caller's notification channels (email, webhook, etc.).
POST /api/notifications/channelsnotifications:writeCreate a notification channel.
PATCH /api/notifications/channels/:idnotifications:writeUpdate a notification channel.
DELETE /api/notifications/channels/:idnotifications:writeDelete a notification channel.
GET /api/notifications/subscriptionsnotifications:readList the caller's notification subscriptions.
PUT /api/notifications/subscriptionsnotifications:writeCreate or update a notification subscription.
DELETE /api/notifications/subscriptions/:idnotifications:writeDelete a notification subscription.
GET /api/notifications/defaultsnotifications:readList org default notification settings.
PUT /api/notifications/defaultsnotifications:adminUpsert one org default.
GET /api/notifications/deliveriesnotifications:readList notification deliveries (the in-app alert feed).
GET /api/notifications/deliveries/unseen-countnotifications:readCount unseen notifications (for the bell badge).
POST /api/notifications/deliveries/:id/seennotifications:writeMark one delivery as seen.

Ownership is enforced inside the handlers

The notifications:* tags only check that you're a member of the active org. Beyond that, channels, subscriptions, and deliveries are scoped to your user — you can't read or modify another member's. A per-user route for an id you don't own returns 404.

Categories

Categories are the stable, user-facing event groups (e.g. deploy.failed, backup.failed, domain.expiring) that subscriptions and defaults key off. They live in code, not the database, so GET /api/notifications/categories is a static registry — each entry has an id, label, description, and defaultEnabled.

curl https://your-host/api/notifications/categories \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN"

Create a channel

A channel is a destination. The config object is shape-checked per kind; secrets in it (webhook signing keys, Slack URLs) are stored encrypted and never returned in full.

POST /api/notifications/channels

Prop

Type

The config shape depends on kind:

Prop

Type

curl -X POST https://your-host/api/notifications/channels \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind":"email","label":"On-call inbox","config":{"address":"ops@example.com"}}'

New channels start enabled: true. An in_app channel is verified immediately; every other kind starts unverified and must be verified (via a test send) before it will deliver — flip verified with PATCH.

Update a channel

Send only the fields you want to change. Changing config on a non-in_app channel resets verified to false, since the destination may have moved.

PATCH /api/notifications/channels/:id

Prop

Type

Subscribe a channel to a category

A subscription is one toggle in the (user, org, category, channel) grid. PUT is an idempotent upsert — send the same triple again to flip enabled. The channelId must be a channel you own.

PUT /api/notifications/subscriptions

Prop

Type

curl -X PUT https://your-host/api/notifications/subscriptions \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"category":"deploy.failed","channelId":"chan_123","enabled":true}'

Org defaults

Defaults seed the subscription grid for new members of the org. Setting a default is admin-only (notifications:admin); reading them is not.

PUT /api/notifications/defaults

Prop

Type

Read the alert feed

GET /api/notifications/deliveries returns your recent deliveries in the active org — this is the history behind the bell icon. GET /api/notifications/deliveries/unseen-count powers the badge, and POST /api/notifications/deliveries/:id/seen clears one.

GET /api/notifications/deliveries

Prop

Type

curl "https://your-host/api/notifications/deliveries?unseen=true&limit=20" \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN"

Errors you might see

400 — invalid channel or missing fields

The kind isn't one of email/webhook/in_app/slack, label is missing, or the config failed its per-kind check (a malformed email, a non-http(s) webhook URL, or a Slack URL that isn't https://hooks.slack.com/...). Subscriptions need category, channelId, and a boolean enabled; defaults need category and a boolean defaultEnabled.

404 on a per-user route

The channel, subscription, or delivery :id doesn't belong to you (or was deleted). List your own with the matching GET route to get valid ids.

On this page