Notifications
Where Anlyon sends alerts about approvals, usage, billing and API keys, and how to configure the channels.
Anlyon sends alerts about approvals waiting for a decision, usage against your allowances, billing and API keys.
Channels
- In-app. Shown in the console.
- Email. Sent to the recipients you list. Early Beta Access includes it, up to 500 emails per workspace per UTC month. The standard Free plan that follows the beta sends no email alerts.
- Webhook. A POST to an endpoint you configure.
- Slack and Discord. Sent to a channel once you connect one.
Configure channels and recipients in the console under Settings → Notifications.
Notification types
| Type | Sent when |
|---|---|
approval_requested |
An approval is waiting for a decision |
quota_warning |
Usage of a monthly allowance crossed one of your alert thresholds |
quota_exceeded |
A monthly allowance with a hard limit reached 100% |
budget_alert |
Projected overage reached your alert target. The alert does not stop usage |
payment_failed |
A payment did not go through |
plan_upgraded, plan_downgraded |
The workspace plan changed |
feature_enabled |
A feature was turned on for the workspace |
api_key_expiring |
An API key is close to its expiry date |
security_alert |
A security event needs attention |
system_alert |
A system event needs attention |
delivery_failure_spike |
Message deliveries are failing at an unusual rate |
Usage alerts cover action executions and delivery messages. Each threshold alerts at most once per month for each of the two. When usage crosses several thresholds at once, only the highest one alerts.
Managing notifications
Listing and counting need notifications:read. Marking read and dismissing need notifications:write. Both scopes are in the default set. Read state belongs to the workspace, so a dismissed notification is gone for everyone.
# List. Add ?unreadOnly=true or ?limit=50 (1 to 100).
curl https://api.anlyon.com/api/v2/notifications \
-H "Authorization: Bearer $ANLYON_API_KEY"
# Count the unread ones
curl https://api.anlyon.com/api/v2/notifications/unread-count \
-H "Authorization: Bearer $ANLYON_API_KEY"
# Mark one as read
curl -X PATCH https://api.anlyon.com/api/v2/notifications/$NOTIFICATION_ID/read \
-H "Authorization: Bearer $ANLYON_API_KEY"
# Mark all as read
curl -X PATCH https://api.anlyon.com/api/v2/notifications/read-all \
-H "Authorization: Bearer $ANLYON_API_KEY"
# Delete one
curl -X DELETE https://api.anlyon.com/api/v2/notifications/$NOTIFICATION_ID \
-H "Authorization: Bearer $ANLYON_API_KEY"
Your own preferences
Every member has their own preferences in each workspace. They hold the notification types you muted. A muted type is left out of your own list and unread count. It is still raised, still sent to email, Slack, Discord and the webhook, and still shown to every other member.
Reading them needs notifications:read. Changing them needs notifications:write. No role is needed. Both calls need a user, so they work from the console and from an OAuth connection. An API key has no user and gets 403 with the code USER_IDENTITY_REQUIRED.
# Read
curl https://api.anlyon.com/api/v2/notifications/preferences/me \
-H "Authorization: Bearer $OAUTH_ACCESS_TOKEN"
# Replace the muted types. Send [] to mute nothing.
curl -X PATCH https://api.anlyon.com/api/v2/notifications/preferences/me \
-H "Authorization: Bearer $OAUTH_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "mutedTypes": ["quota_warning"] }'
{
"success": true,
"data": {
"mutedTypes": ["quota_warning"],
"updatedAt": "2026-10-03T12:00:00.000Z"
}
}
mutedTypes takes up to 12 notification types. In the console this is Settings > Notifications > My notifications.
Workspace preferences
These decide where the workspace’s alerts are sent and which types are raised, for every member.
| What you do | Scope | Role, for a console session or an OAuth connection |
|---|---|---|
| Read workspace preferences | notifications:read |
Any member |
| Update workspace preferences | notifications:manage |
Admin or owner |
| Send the test webhook | notifications:manage |
Admin or owner |
notifications:manage is a privileged scope. No key gets it by default. An OAuth connection gets it from the Notification channels group, which is off unless you turn it on. In the console, a member sees these settings and an admin changes them.
OAuth tokens issued before 2026-10-03 do not carry notifications:write or notifications:manage. An existing OAuth client must re-consent before it can mark notifications read, dismiss them, or change notification settings. API keys created before that date that changed notification settings with notifications:read need the new scope.
Read
curl https://api.anlyon.com/api/v2/notifications/preferences \
-H "Authorization: Bearer $ANLYON_API_KEY"
{
"success": true,
"data": {
"emailEnabled": true,
"webhookEnabled": false,
"inAppEnabled": true,
"slackEnabled": false,
"discordEnabled": false,
"emailRecipients": ["owner@example.com"],
"webhookUrl": null,
"hasWebhookSecret": false,
"quotaAlertThresholds": [50, 75, 90, 100],
"enabledTypes": ["approval_requested", "quota_warning", "quota_exceeded"]
}
}
The webhook secret is never returned. hasWebhookSecret says whether one is set.
Update
Send the fields you want to change.
curl -X PATCH https://api.anlyon.com/api/v2/notifications/preferences \
-H "Authorization: Bearer $ANLYON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"emailEnabled": true,
"emailRecipients": ["oncall@example.com"],
"quotaAlertThresholds": [60, 80, 95, 100]
}'
| Field | Meaning |
|---|---|
emailEnabled, webhookEnabled, inAppEnabled, slackEnabled, discordEnabled |
Turn a channel on or off |
emailRecipients |
Up to 50 email addresses |
webhookUrl, webhookSecret |
The webhook endpoint and the secret that signs its payloads. null clears either one |
quotaAlertThresholds |
Up to 20 whole percentages from 0 to 100. The default is 50, 75, 90 and 100 |
enabledTypes |
The notification types to send |
Webhook notifications
Configure the endpoint
curl -X PATCH https://api.anlyon.com/api/v2/notifications/preferences \
-H "Authorization: Bearer $ANLYON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhookEnabled": true,
"webhookUrl": "https://your-app.com/webhooks/anlyon",
"webhookSecret": "a-long-random-string"
}'
Send a test payload to an endpoint before you save it:
curl -X POST https://api.anlyon.com/api/v2/notifications/preferences/test-webhook \
-H "Authorization: Bearer $ANLYON_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "webhookUrl": "https://your-app.com/webhooks/anlyon", "webhookSecret": "a-long-random-string" }'
Payload
{
"event": "notification.quota_warning",
"timestamp": "2026-10-01T15:00:00.000Z",
"workspaceId": "2f8a1f72-7cf9-4fef-95e8-df9de5f2f5d0",
"data": {
"notificationId": "...",
"type": "quota_warning",
"priority": "medium",
"title": "Action executions: 75% of monthly allowance used",
"message": "7,500 of 10,000 used. ...",
"metadata": { "dimension": "actionInvokes", "month": "2026-10", "threshold": 75, "percent": 75 }
}
}
The request carries X-Anlyon-Event and X-Anlyon-Timestamp headers.
Signature
When a webhook secret is set, the request also carries X-Anlyon-Signature: sha256=<hex>. The value is the HMAC-SHA256 of the raw request body, keyed with your webhook secret. With no secret set, the request is unsigned.
This is a different format from the Anlyon-Signature header on signed deliveries. The SDK’s Receiver class verifies Anlyon-Signature and does not verify this header. Verify it yourself:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyNotification(rawBody: string, header: string | undefined, secret: string): boolean {
if (!header) return false;
const expected = `sha256=${createHmac('sha256', secret).update(rawBody).digest('hex')}`;
const a = Buffer.from(expected);
const b = Buffer.from(header);
return a.length === b.length && timingSafeEqual(a, b);
}
The signature covers the body and nothing else. It carries no timestamp and no environment, so it does not bound replay age.
How it behaves
- An alert reports. A
budget_alertreports projected overage, and usage continues. - A notification webhook is one POST. Make your handler safe to call more than once, and do not rely on its arrival for anything that must happen.
- The notification signature is separate from the delivery signature. It covers the body and names no environment. See Webhook signature verification.

