Skip to main content

Fraud caps

Fraud caps are your account’s anti-abuse limits. Each outbound send runs against two thresholds: a per-minute velocity cap (how fast) and a daily-spend cap in cents (how much). When a cap trips, the send is rejected — which is exactly what you want when something on your side, or an attacker on theirs, starts generating anomalous traffic. The platform sets floors — conservative defaults per channel — that apply even with no override configured. This page shows how to read the floors, tighten a channel below its floor as a wallet guard, and size a cap for a real workload. The endpoint is GET / PUT /api/v1/settings/compliance/fraud-caps. Reads are open to any authenticated member of your organization; writes are restricted to owners. Full request shapes are in the settings API reference.

What a fraud cap is — and is not

A fraud cap is an abuse control, not a throughput control. Too-low per-minute limits generate 429 rejections; too-high limits let a leak or a toll-fraud attack run up spend before anyone notices. Two different knobs answer those questions on this platform — don’t conflate them: Raise your envelope with Channel rate overrides only after sizing the fraud guard here. A send must pass both gates.

Reading floors and overrides

GET /api/v1/settings/compliance/fraud-caps returns one object with two blocks:
  • channels — one entry per covered channel (sms, mms, whatsapp, rcs, viber, email, telegram, push, web_chat, messenger, line, instagram, fax, apple_messages). Each entry carries max_per_min and max_daily_spend_cents — your override, or null when the floor applies — plus floor_per_min and floor_daily_spend_cents from the platform.
  • voice — the envelope for outbound calls: max_calls_per_min, max_daily_spend_cents, a per-destination-country country_max_per_min map (see below), and the voice floors.
Read the object back before every change — max_per_min: null on a channel means “floor applies,” not “unlimited.” If the settings lookup fails transiently, the response degrades to floors-only (all overrides null) rather than a 5xx. The dashboard panel still renders, and enforcement keeps using the floors — a read error never widens your exposure.

Writing overrides

PUT /api/v1/settings/compliance/fraud-caps is owner-only. The body carries two optional blocks, and both are sparse: only channels you include are touched — everything else keeps its stored value. Inside a channel entry, a null leaf clears just that override and reverts to the floor.
Because an unset override always falls back to the floor, clearing a cap (send null) is safe — it widens back to the platform guard, never to “no guard.” To restore a whole channel’s defaults, clear both leaves and omit nothing else:
Values are integers within a sanity ceiling the send path also enforces, so a value accepted here can never be silently rejected at dispatch time. A 422 on the write means a leaf was non-integer, non-positive, or above that ceiling — fix the payload and retry. The voice.country_max_per_min map is replaced wholesale on every PUT that includes it: send the entire map you want active. An empty map clears all per-country caps.
voice.max_calls_per_min caps the overall outbound dial rate, while voice.country_max_per_min clamps one named ISO country independently. On voice, 0 is a legal value: a country’s mid-attack “stop dialing this destination” lever that doesn’t exist on the messaging channels.

How voice fraud interacts with auto-blocks

Per-country caps are one of three voice-side layers you should understand together:
  1. Platform floors — always-on per-tenant and per-country call-rate guards, plus a curated premium-rate prefix blocklist.
  2. Your overrides — the voice block above: overall velocity, daily spend, and per-country rates you tighten below the floors.
  3. Automatic per-destination blocks — when a detector sweep sees traffic-pumping (IRSF revenue-share) or a Wangiri callback burst concentrated on one specific number, it applies a reversible, self-expiring block on exactly that destination. Legitimate calls to every other number are unaffected.
Sustained attacks often express as a per-country spike before any single number trips a block: if your account dials into an expensive destination at a rate you never approved, cap that country here (or set it to 0) while the anomaly is investigated. Full coverage of the auto-block categories, lifetimes, and read endpoints is in Voice destination auto-blocks.

Worked sizing examples

US toll-free SMS, a marketing dispatcher

A mid-size sender runs a campaign that delivers about 1,200 SMS per minute on peak days, with a verified sender registration. The account has never had a fraud incident, but an operator wants damage-bound limits in case a queue duplicates jobs or a token leaks.
  • Velocity. 1,200 / 60 = 20 sends per second. Leave headroom for bursts: set sms.max_per_min to the sustained peak — 1200 — not the average.
  • Spend. At 0.0075persegmentand 1.2segmentspermessage,peakhourspendis1200×60×1.2×0.00750.0075 per segment and ~1.2 segments per message, peak hour spend is `1200 × 60 × 1.2 × 0.0075 ≈ 648/hr. A daily budget of roughly 8 peak hours is 500000cents ($5,000). Setsms.max_daily_spend_cents` there — the first anomalous spike that runs past a working day cuts itself off.
  • Verify. PUT the map, then GET the endpoint: sms shows your values in max_per_min and max_daily_spend_cents, and the floors appear alongside (so you can see the delta you introduced). Run a batch against the cap — at 20+ msg/sec you’ll see the floor of rejections stop exactly at the limit you chose, while a second run under the cap completes cleanly.

Voice IVR campaign, outbound customer callbacks

A utility dials opted-in customers for payment reminders from an IVR-driven dialer: about 25 concurrent legs at any moment, only US destinations, ~$40/day in voice spend.
  • Overall rate. Set voice.max_calls_per_min to 30 — a hair above the observed 25/minute peaks — so a wedged dialer loop rejecting-retrying can’t sustain a spike.
  • Country clamp. Cap voice.country_max_per_min on the one destination country the campaign touches (US: 12) so a misrouted campaign to a premium-tier destination is cut at the source.
  • Spend. Set voice.max_daily_spend_cents to 6000 ($60) — 1.5× the normal daily bill, so anomalies still stop but a busy Monday doesn’t stall.
In both cases, the cap should sit above your legitimate peak and below any plausible attack volume — treat the floor as a backstop, and your override as the primary budget boundary.

Audit trail and verification

Every PUT writes an entry to your audit log naming the capped keys — the resulting override map and the cleared list — so a raised or cleared guard is part of the trail, not a silent change. Owners verify a change in three steps, the same loop as on channel-rate-overrides:
  1. Set. PUT the overrides (owner role).
  2. Read back. GET the endpoint and confirm each field carries your values; cleared leaves show null (floor applies).
  3. Confirm on the send path. Send on the capped channel at your historic rate and watch rejections stop at the new boundary — previously the same burst only stopped at the platform floor.
The same control is available under Settings → Compliance in the dashboard: each channel’s current override is shown next to the platform floor, and a voice block carries the per-country map editor. Owners see the write action; other members see the effective caps. Reads and writes on this surface are tenant-scoped — you only ever see and change your own organization’s limits.