DomainOpsDomainOps

Notifications API

Configure per-channel notification settings (digest + instant), send test messages, query delivery history, and manage exposure-alert subscriptions.

Channel settings

GET/api/v1/notifications/settingsAuth required

Return the caller's notification_settings rows. Each (notification_type, delivery_class) pair is its own row — e.g. a team can have an instant+slack row and a digest+slack row configured independently.

Response

json
[
  {
    "id": "uuid",
    "notification_type": "slack",
    "delivery_class": "instant",
    "is_enabled": true,
    "config": { "webhook_url": "https://hooks.slack.com/services/..." }
  },
  {
    "id": "uuid",
    "notification_type": "slack",
    "delivery_class": "digest",
    "is_enabled": true,
    "frequency_days": 7,
    "notification_time": "09:00:00",
    "config": { "webhook_url": "https://hooks.slack.com/services/..." }
  }
]
PUT/api/v1/notifications/settings/:typeAuth required

Upsert the settings row for a given (type, delivery_class). :type must be one of email, webhook, slack, pushover, teams. delivery_class is required in the body so digest and instant rows are addressed independently. Digest delivery is available on email, slack and teams only — a digest row for webhook or pushover is rejected with 400.

Request Body

ParameterTypeRequiredDescription
delivery_classstringYes"instant" or "digest"
is_enabledbooleanNoEnable or disable this channel for the given delivery class
frequency_daysnumberNoDigest cadence (1, 7, 14, or 30). Digest delivery only.
notification_timestringNoLocal time of digest send, HH:MM:SS. Digest only.
configobjectNoChannel-specific config, e.g. { "webhook_url": "https://..." }
min_severitystringNoSeverity floor for instant exposure alerts: critical | high | medium | low | info. Default medium. Ignored for digest rows.

Example request

json
{
  "delivery_class": "digest",
  "is_enabled": true,
  "frequency_days": 7,
  "notification_time": "09:00:00",
  "config": { "webhook_url": "https://hooks.slack.com/services/..." }
}

Response

json
{
  "id": "uuid",
  "notification_type": "slack",
  "delivery_class": "digest",
  "is_enabled": true,
  "frequency_days": 7,
  "notification_time": "09:00:00",
  "config": { "webhook_url": "https://hooks.slack.com/services/..." }
}

Test send

POST/api/v1/notifications/test-sendAuth required

Queue a real test notification for a channel and recipient. The worker delivers it on its next cycle (typically under five minutes) and the attempt — success or failure — then appears in the delivery log under the returned id, making this an end-to-end delivery check rather than a config validation.

Request Body

ParameterTypeRequiredDescription
channelstringYesemail, webhook, slack, pushover, or teams
recipientstringYesEmail address for email; webhook URL for webhook/slack/teams; Pushover user key for pushover.
subjectstringNoOptional custom subject for email
metadataobjectNoOptional metadata echoed in the test payload

Response

json
HTTP 201 Created

{
  "id": "uuid",
  "channel": "slack",
  "recipient": "https://hooks.slack.com/services/...",
  "status": "queued",
  "created_at": "2026-08-18T09:00:00Z"
}

Delivery log

GET/api/v1/notifications/logAuth required

Paginated notification delivery history, most recent first. One entry per delivery, so channels always holds a single value — the channel filter matches it exactly. status is success (delivered), failed (retries exhausted) or partial (attempted, will retry). error_message carries the last failure reason where there is one.

Query Parameters

ParameterTypeRequiredDescription
channelstringNoemail | webhook | slack | pushover | teams
statusstringNosuccess | failed | partial
limitnumberNoMax 100, default 50
offsetnumberNoRows to skip, default 0

Response

json
[
  {
    "id": "uuid",
    "channels": ["slack"],
    "status": "success",
    "message_preview": "SSL expiry — example.com",
    "sent_at": "2026-04-19T09:00:00Z",
    "error_message": null,
    "metadata": null
  }
]