Skip to main content

Spend alerts, burn rate, and the velocity-anomaly model

Orbit protects a prepaid wallet with three instruments that complement each other: threshold alerts you configure yourself, a burn-rate projection that forecasts runway, and velocity-anomaly detection that flags a sudden spend surge and can choke it automatically. This page explains what each one answers, how the anomaly model’s math works, what the ledger records, how the auto-mitigation throttle behaves, and where escalations and incidents fit. The endpoint surface is the Billing overview; request and response schemas are the Billing API reference. The full incident model lives on on-call and the escalation-policy model.

The three instruments, side by side

Threshold alerts are the instrument you shape. You pick a threshold type — spend_percent (share of a reference spend), spend_amount or balance_remaining (absolute cents), or daily_spend (cents per day) — a threshold value, up to 20 email and/or SMS recipients, and the action that fires when the line is crossed. A scheduler evaluates alerts on a 10-minute tick. Prefer notify: an operator reviews the hit and decides. pause_outbound stops outbound sending until you reset the alert in the dashboard. Threshold alerts are tenant-owned controls: you own both the line and the consequence. Burn rate answers a runway question, not an abuse one. It averages your daily spend over a lookback window (?days=, default 30, up to 90) and divides the current wallet balance by that average to project projected_days_remainingnull when there is no recent spend to extrapolate from. Credit rows (top-ups) are excluded from the average, so a recent top-up doesn’t read as a burn surge. GET /api/v1/billing/spend-series returns the same window plus a forward projection and anomaly flags. Burn rate never acts; it informs auto-top-up thresholds and your own capacity planning. Velocity anomaly detection is the instrument neither of the above covers: a sudden acceleration of spend. Absolute thresholds only bite once the line is reached, and burn rate is a smoothed average — neither spots a compromised API key or a hijacked campaign in its first minutes. The anomaly detector compares today’s velocity against your own trailing baseline per channel and flags a surge before a hard cap is exhausted.

Velocity anomaly detection — the model

The detector is pure window math over your debit ledger. For every channel (sms, whatsapp, voice, email, rcs, agents, other) it builds a pair of numbers, plus a synthetic all aggregate that catches a surge spread thinly across channels:
  • Baseline — the average daily spend over the trailing 14 complete UTC days (today excluded). Manual operator wallet adjustments (admin_grant / admin_deduct rows and admin* references) are excluded from both sides, so bookkeeping never looks like usage.
  • Today — spend so far in the current (incomplete) UTC day, extrapolated to a full-day rate: projected = today_spend / day_fraction_elapsed. The fraction is floored at one hour of the day, so a one-minute burst at 00:03 does not project to an absurd rate.
A channel is flagged when both of these hold:
  1. Absolute floor — the projected daily rate clears **250/day(25,000cents).Thisgatefallsfirst,anditiswhatkeepsatenantspending250/day** (25,000 cents). This gate falls first, and it is what keeps a tenant spending 0.10/day from generating a page when $0.30/day is a 3x surge.
  2. Surge multiple — the projected rate reaches 10x the baseline daily average. A new tenant with no baseline history at all is treated as a cold-start surge the moment the projection clears the floor — there is no prior spend to compare against, and an instant $250/day projection for an org that never spent is itself the anomaly.
Each flagged channel reports its baseline, today’s spend, the projection, the surge ratio (null on a cold start, where the ratio is undefined), and a severity. Severity is critical when the ratio reaches 25x the baseline (2.5x the 10x threshold) or the absolute projection reaches $1,250/day (5x the floor); otherwise it is high. Both the dashboard read and the on-call bridge below go through the same evaluator, so no two surfaces can disagree on what counts as a surge. No configuration is required and none is accepted — the tunables are platform defaults. Your own controls remain the threshold alerts above; the anomaly model exists to catch what a fixed line you picked yesterday can’t.

The anomaly ledger

Two reads expose the model:
  • GET /api/v1/billing/spend-anomaly — the current evaluation. Returns the detected anomalies, the applied tunables (surge_multiplier, min_projected_daily_minor, baseline_days), and day_fraction_elapsed so you can re-derive any ratio yourself. Each newly detected channel also lands in the fraud-review queue for operators — deduplicated to one entry per (organization, channel, UTC day), so polling the endpoint can’t spam the queue.
  • GET /api/v1/billing/spend-anomaly/ledger — the historical ledger of everything the detector has recorded for your organization (the dashboard poll and the continuous background sweep both write to it). Optional from/to ISO timestamps bound the window; limit is bounded to 500 (default 100), newest first. Every entry carries the channel, surge ratio, baseline/today/projected spend in minor units, any auto-mitigation applied, and the review’s triage status (open / triaged / dismissed / escalated) with its acknowledgement and resolution timestamps.
Use the current read for “what is on fire right now” and the ledger for forensics — trend analysis, chargeback attribution, and post-incident review.

Mitigation — the self-expiring throttle

Detection closes its own loop. When a flagged channel maps onto an enforceable fraud cap (sms, whatsapp, rcs, email, voice), Orbit applies a graduated, reversible clamp on that channel’s per-minute send rate:
  • high severity → throttle: the channel is clamped down to 10 sends or calls per minute. Legitimate low-volume traffic still flows; a toll-fraud pump is choked.
  • critical severity → pause: the clamp is 0 per minute — every send or call on that channel is refused until the mitigation expires or you clear it.
Channels without a matching guard cap (agents, other, the synthetic all) are never auto-mitigated — the operator alert still fires for them. The clamp has three properties worth modeling:
  • Min-only. It can only ever lower the effective per-minute cap the fraud guards enforce. It can never raise your own configured cap, so an anomaly can never weaken protection you already set.
  • Self-expiring. Every mitigation record carries an expires_at, capped at 6 hours (and never longer than the rest of the UTC day). An automatic throttle must not linger on a false positive: when the record expires the guards ignore it and the channel reverts on its own — no revert job, no operator action.
  • Tenant-clearable. You can clear an active mitigation early from the fraud-caps surface in the dashboard when you’ve confirmed the surge is legitimate (a real launch, a known campaign).

Escalation and incidents

POST /api/v1/billing/spend-anomaly/escalation bridges the anomaly signal onto the on-call pipeline. Send the caller’s own escalation policy in the request body — the same policy shape the On-Call API accepts: ordered steps, each with a target (a rotation or a static member list), the channels to page, and an acknowledge-wait window. The endpoint re-evaluates your current spend velocity and, when an anomaly is flagged, returns the incidence plane as pure compute:
  • an incident snapshot anchored to your policy (open, pages_fired: 0), and
  • the flattened plan — the ordered page timeline with total_pages, next_tick_at, and whether the policy is exhausted.
When nothing is flagged the response is detected: false with no incident plane. Nothing is persisted or sent by this endpoint: your driver (the dashboard’s wire-escalation affordance, or the background sweep) walks the returned plan through the on-call incident tick/transition endpoints, same as any other incident. The full rotation, timeline, and incident-state model — including the high-water mark that makes retries idempotent — is on on-call and the escalation-policy model.

Example flows

Create a threshold alert:
POST /api/v1/billing/alerts
201
Read the current anomaly evaluation:
GET /api/v1/billing/spend-anomaly
Read the historical ledger:
GET /api/v1/billing/spend-anomaly/ledger?limit=50
All monetary fields are wallet-currency minor units (cents). cooldown_hours on an alert caps how often the same alert re-notifies; the anomaly ledger has no cooldown — it is the append-only record, while deduplication happens on the operator-facing queue per (organization, channel, UTC day).

Next steps