Skip to main content

Spend caps on the dashboard

Your spend cap is the ceiling you set on your own prepaid wallet — separate from the platform fraud envelope every send is measured against. This page walks the full loop: where the cap panel lives and how it relates to the wallet, how to set a monthly budget and threshold rules with real hard cutoffs, how to rehearse the over-cap path in sandbox before it fires on live traffic, what an over-cap send returns, and the three recovery levers available when one trips.

1. Where the cap panel lives — and how it relates to the wallet

Everything tenant-owned lives under Billing → Alerts in the dashboard. The page holds two controls:
  • The monthly-budget card — a dedicated card at the top of Billing → Alerts with an inline editor. It stores org monthly_budget_cents, the denominator every spend_percent rule computes against. The same value is editable under Settings → Account → General (both surfaces write one value). Until you set it, spend_percent rules report themselves inapplicable and the dashboard disables the percent option with a “set a monthly budget first” pointer.
  • The alert-rules list — the threshold rules themselves: metric, threshold, recipients, action, cooldown. Create, read, and dry-run them here.
The relationship to the wallet is one-directional: the wallet is the ledger your usage debits from (the full pipeline — top-up, rating, FX, ledger — is on Billing, wallet, and usage concepts); the cap is a set of rules over that ledger. Rules never move money — they read month-to-date spend, today’s spend, percent-of-budget, or the live balance, and they either notify or flip an outbound gate flag. The wallet itself knows nothing about your rules.

2. Set a cap: budget first, then a layered rule set

Step 1 — set the monthly budget. Without it, percent-based rules are inert. There is no public budget endpoint — set it on the monthly-budget card in Billing → Alerts, or under Settings → Account → General. Rules created via the API read the same value either way. Step 2 — create the rules. The API surface is GET/POST /api/v1/billing/alerts[/:id], plus POST /:id/test-fire for a no-side-effects dry run — all mirrored on the dashboard. This example builds a two-layer ladder: a soft notification at 70%, and a hard pause at 90%:
The four metrics map onto the classic ladder: spend_percent (share of monthly budget), spend_amount (month-to-date cents), daily_spend (today’s cents), and balance_remaining (a floor, compared less-than). A layered set keeps any single threshold from being your only line of defense: the 70% notify gives you hours of warning, so the hard 90% stop — when it does fire — is never a surprise. Hard vs soft cutoff. The action chooses the cutoff character:
  • notify — soft. Recipients get email/SMS; traffic untouched. Use for warning bands.
  • pause_outbound — hard. Sets the org’s outbound-paused flag; new sends return 402 SENDING_PAUSED until a human clears the alert in the dashboard.
  • block_outbound — hard, operator-reviewed. The stricter gate used when the stop should hold until someone looks at it, not just until someone clicks clear.
Recipient lists can be empty on pause/block rules when the point is enforcement, not notification. Dry-run before you rely on it. POST /api/v1/billing/alerts/:id/test-fire evaluates a stored rule against today’s spend and balance and reports whether it would trigger — without notifying anyone, stamping the rule, or gating traffic. Test-fire every new rule before it guards real traffic. The field-by-field reference (validation ranges, the worked 201 create response, cooldown semantics) is Spend caps, budget alerts, and auto-cutoff. Steps below stay deliberately thin and point there.

3. Rehearse the over-cap path in sandbox

A pause rule is only tested when it fires, and firing it on live traffic costs a real incident. Rehearse it against a sandbox key (dv_test_sk_*):
  1. Calc the probe size. Set the sandbox budget to a small value (e.g. $5). One message to a magic-number recipient resolves delivered per the sandbox magic-numbers table (for pause drills you do not need a failure scenario — you need a countable, cheap send). The what-if preview endpoint from api-recipes task 22 prices a send before you fire it.
  2. Arm a low threshold. Create a spend_amount rule with a threshold of one message’s cost (or a daily_spend rule with a handful of cents) and action_on_hit: "pause_outbound". Low thresholds in sandbox are free; in production this same shape is how you test without touching live traffic.
  3. Send until the tick trips. Fire one sandbox send per the numbered example below; wait for the billing scheduler’s 10-minute tick to evaluate; watch the recipients receive the rule’s name plus the observed value, then confirm the paused flag.
  1. Read the state. GET /api/v1/billing/alerts shows the rule’s last_triggered_at stamped; the dashboard wallet header shows the org paused.
In live mode the same sends debit real money and the pause gate refuses real traffic. Rehearse in sandbox or on a staging organization — the rule shape is identical either way.

4. What happens on over-cap

The response differs by layer, and reading the error code wrong is the most common misdiagnosis: Suppression behavior: the refusal happens before the channel leg dispatches, so an over-cap send never reaches the carrier, never debits the wallet, and never generates a delivery receipt. Your webhook sees nothing for the refused send — the 402 response is the entire signal. If the send path retries, it re-fails against the gate; dedupe is on you via idempotency. Full remediation code-by-code lives in Troubleshooting: billing-gate outbound blocks; the wallet-empty branch is Troubleshoot INSUFFICIENT_BALANCE (402).

5. Recover: raise the cap, top up, or split traffic

Three levers, in order of use:
  1. Raise the cap. When the rule was too tight for legitimate volume, edit the rule’s threshold_value in Billing → Alerts, then clear the tripped gate with POST /api/v1/billing/alerts/reset-outbound (owner or admin; the dashboard’s clear button calls the same route). The gate re-arms once you have cleared, with the new threshold in effect from the next tick.
  2. Top up. When a balance_remaining floor or INSUFFICIENT_BALANCE was the stop, auto top-up keeps the wallet funded at a chosen trigger level so the floor rule trips less; manual top-up ends the current stoppage immediately.
  3. Split traffic. When one sender profile keeps smashing the org-wide line, move it to a sub-account with its own monthly latched cap (reseller pattern, Spend caps §4) — the blast radius shrinks to that child account and the rest of the org keeps sending.
Read the gate before you clear, not after:clearing without understanding the spend shape re-trips the same rule inside your cooldown window.

6. Per-channel and per-scope caps

  • Org-wide rules (Billing → Alerts) measure one org-wide metric — there is no per-country org alert; the metric family covers percent/amount/daily/balance, not destination.
  • Agent LLM spend has its own daily USD cap under Settings → Agents (GET/PUT /api/v1/settings/agents/spend-cap) — the details are in Spend caps §3, refused with AGENT_DAILY_SPEND_CAP_REACHED (429).
  • Sub-accounts (resellers) get a hard per-child monthly latch that stays tripped until a new UTC month or a refund releases it — per destination without per-country selection.
  • The fraud envelope’s per-channel daily ceilings exist precisely because org alert rules are global — they take up the per-channel slack your rules cannot express.

7. Pair with anomaly rules and recipes

The usage-anomaly rules (spend, outbound volume, delivery rate) are read-only over your ledger — they fire-event feeds and Notification Center pings, never gate. Cross-link them on top of a hard cap exactly as the fixed-threshold / detector pairing is done intentionally: the anomaly tells you where to look, the cap enforces while you look. Two useful recipes from api-recipes: task 22 prices a send before you fire thresholds (the sandbox drill above), and the errors-as-recipes table maps the refund/retry semantics of 402 codes to your clients.

8. Next: API-level budgets

The spend cap guards money. To guard request volume per API key — a leaked-key or runaway-integration signal that shows up before any spend moves — set the per-key monthly quota and usage-alert thresholds in Per-API-key usage budgets and threshold alerts. An org can be well under its spend cap while one key is burning through a quota; the two layers are complementary and both are tenant-owned.
For the endpoint-by-endpoint field reference see Spend caps, budget alerts, and auto-cutoff and the Billing API reference.