Skip to main content

Usage & delivery anomaly alert rules

Define org-scoped alert rules that watch the signals that move a CPaaS account: SMS delivery rate, outbound message volume, and spend. When the metric breaks your threshold — or deviates sharply from its own learned baseline — the rule fires an in-app notification the whole team sees in the dashboard’s Notification Center. Rules are read-only over your account. Evaluation aggregates your already-persisted message and billing-ledger rows; the only writes are alert-rule state and the notification it fires. No outbound traffic ever results from a rule. This complements In-dashboard notifications and the Notification Center (the surface rules notify on) and Per-API-key usage budgets and threshold alerts (a browser-local tripwire; everything on this page is org-scoped and shared with your team).

Endpoints

All endpoints share the standard { "data": ..., "meta": ... } envelope and are tenant-scoped. A tenant can hold up to 50 rules.

Auth requirements

  • Reads (GET ..., GET .../events) — a valid API key/JWT whose scopes include usage:read.
  • Writes and evaluate-now (POST, PATCH, DELETE, POST .../evaluate) — additionally require an org role of owner, admin, or developer. The audit log records create/update/delete with the acting user.

Rule shapes

Each rule targets one metric, using one of two modes.

Metrics

Delivery rate and volume are computed over your outbound messages with the same status filters the dashboard’s delivery KPI card uses, and spend is aggregated from wallet-ledger debits excluding admin adjustments — so an alert fires on exactly the numbers the dashboard shows.

Threshold mode (default)

Compares the metric’s value over a trailing window against a fixed number.
  • comparator: one of gt, gte, lt, lte
    • lt / lte — “must stay above X” (e.g. delivery rate below 95%)
    • gt / gte — “must stay below X” (e.g. volume above 10k/day, spend above $100)
  • threshold: a finite number on the metric’s native unit
  • window_days: the trailing window the threshold aggregates over, 1–30 (default 7)
A threshold rule cannot exist without both a comparator and a threshold — create and update both reject it (422).

Anomaly mode

Compares the newest complete UTC day against a learned 28-day baseline using a z-score classifier. You set no threshold — “unusual for your account” is the trigger. For delivery rate it detects a downward drop; for volume and spend, an upward spike (the metric on volume/spend rules is inverted internally so a spike registers the same way). Anomaly rules must not carry comparator/threshold at create time (they are ignored); pass only mode: "anomaly" plus window_days, cooldown_hours, notify_channels, enabled.

Field reference (create / update body)

notify_channels currently accepts only in_app. Alerts surface through the existing dashboard notification channel (the bell / Notification Center); email or webhook fan-out is not yet on this surface.

The fired event lifecycle

A scheduler-driven sweep continuously evaluates every tenant that has at least one rule, and POST /usage/alert-rules/evaluate runs the same evaluation on demand for your tenant. On every evaluation tick, each enabled rule updates its runtime fields (last_evaluated_at, last_status, last_value) — even in a breach. An event is appended to your fired-alert feed (max 50, newest first) and a notification pushed only when:
  • the rule’s status transitions into breached, or
  • it stays in breach and the cooldown_hours re-notify window (default 24h) has elapsed since the last notification.
While the rule stays in breach but inside the cooldown, state still updates but no new event/notification is emitted — the same signal does not re-page you for 24 hours. A metric that cannot be resolved (no data in the window, or a provisioning gap) is reported as insufficient_data and never fires a false alert.

Event payload

Each entry in GET /usage/alert-rules/events: Poll GET /usage/alert-rules/events to consume alerts from an API integration, or open the Notification Center in the dashboard.

Where alerts land in the dashboard

A firing rule reuses the in-app notification channel: it appears in the bell dropdown and the Notification Center with severity warning, titled Usage alert: <your rule name>, with the threshold/anomaly sentence as the body and a deep link to the Insights page. See In-dashboard notifications and the Notification Center for triage/read/dismiss semantics.

Example: delivery-failure-rate alert

Create a rule that fires when SMS delivery rate over the trailing week falls below 95%, and re-fires at most once a day while it stays breached:
Response (201):
Evaluate now (optional — the scheduler sweep also evaluates it on its own cadence):
Then read the fired feed:
A mode: “anomaly” variant — pick up when the newest day’s delivery rate deviates sharply from the learned 28-day baseline, without fixing a threshold:

Troubleshooting

422 says “comparator is required for a threshold rule”. Pass both comparator and threshold whenever the rule is threshold mode (create, and any update on a threshold rule; mode defaults to threshold). A rule’s last_status reads insufficient_data. The metric could not be resolved in the window — usually zero outbound messages (or wallet debits, for spend rules) in the window. Evaluation reports no value rather than firing on a fabricated 0%. The rule fires fewer notifications than expected. That is cooldown semantics: while a rule stays in breach, it re-notifies only once per cooldown_hours (default 24h); new breach transitions always notify immediately. You want email or webhook instead of the dashboard notification. The only configured channel today is the dashboard notification (notify_channels: ["in_app"]). Poll the fired-event feed to integrate alerts into your own systems.