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, sms, webhook, slack, pushover, teams. delivery_class is required in the body so digest and instant rows are addressed independently.

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://..." }

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

Send a one-off test notification to verify a channel is configured correctly. Does not persist to the notification log.

Request Body

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

Response

json
HTTP 201 Created

{
  "channel": "slack",
  "recipient": "https://hooks.slack.com/services/...",
  "status": "sent",
  "created_at": "2026-04-19T20:00:00Z"
}

Delivery log

GET/api/v1/notifications/logAuth required

Paginated notification delivery history. The channel filter matches rows whose channels array contains the given value.

Query Parameters

ParameterTypeRequiredDescription
channelstringNoemail | sms | webhook | slack | pushover | teams
statusstringNosuccess | failed | partial
limitnumberNoMax 100, default 50

Response

json
[
  {
    "id": "uuid",
    "channels": ["slack", "email"],
    "status": "success",
    "message_preview": "SSL expiring in 7 days: example.com",
    "sent_at": "2026-04-19T09:00:00Z",
    "metadata": { "domain": "example.com" }
  }
]

Exposure subscriptions

Per-user subscriptions that control which exposure events (new findings, severity thresholds) trigger alerts, via which channels. Scoped to a single domain or the whole team.

GET/api/v1/notifications/exposure-subscriptionsAuth required

List the caller's exposure subscriptions for the current team.

Response

json
[
  {
    "id": "uuid",
    "domain_id": "uuid-or-null",
    "subscription_type": "critical_exposure_only",
    "alert_threshold": "high",
    "alert_on_new_exposure": true,
    "notification_channels": ["slack", "email"],
    "is_enabled": true
  }
]
POST/api/v1/notifications/exposure-subscriptionsAuth required

Create an exposure subscription.

Request Body

ParameterTypeRequiredDescription
domain_idstring (uuid)NoScope to a single domain; omit to cover all team domains.
subscription_typestringYescritical_exposure_only | all_exposures | all_team_exposures
alert_thresholdstringYescritical | high | medium | low | info
alert_on_new_exposurebooleanNoDefault true — alert on every new exposure event meeting the threshold.
notification_channelsarrayYesNon-empty array of channels: email | sms | webhook | slack | pushover | teams
is_enabledbooleanNoDefault true.
configobjectNoFree-form per-subscription config.

Response

json
HTTP 201 Created

{
  "id": "uuid",
  "domain_id": "uuid",
  "subscription_type": "critical_exposure_only",
  "alert_threshold": "high",
  "alert_on_new_exposure": true,
  "notification_channels": ["slack", "email"],
  "is_enabled": true
}
PUT/api/v1/notifications/exposure-subscriptions/:idAuth required

Update a subscription owned by the caller.

Request Body

ParameterTypeRequiredDescription
subscription_typestringNoSee create endpoint
alert_thresholdstringNoSee create endpoint
alert_on_new_exposurebooleanNo
notification_channelsarrayNoNon-empty array of channels
is_enabledbooleanNo
configobjectNo

Response

json
{
  "id": "uuid",
  "alert_threshold": "critical",
  "is_enabled": true
}
DELETE/api/v1/notifications/exposure-subscriptions/:idAuth required

Delete an exposure subscription owned by the caller.

Response

json
{
  "id": "uuid",
  "deleted": true
}