> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# SMS-pumping (AIT) protection: read the risk score before you send

> Score any destination 0-100 before committing SMS spend — composite risk verdict, per-factor artificial-traffic breakdown, and Verify AIT analytics — as one pre-send posture.

# SMS-pumping (AIT) protection: read the risk score before you send

SMS-pumping — also called artificial-inflation of traffic (AIT) — is the fraud pattern where an attacker (or a complicit premium-rate number owner) drives fake traffic to destination numbers that pay out on inbound SMS. The attacker converts stolen signup forms, bot-driven OTP requests, or compromised senders into messages to IRSF (International Revenue Share Fraud) ranges and premium-rate destinations; the platform bills every accepted leg, and the fraudster pockets the carrier payout. Orbit ships three API surfaces that expose this pattern to you before and after it costs money. This guide explains what each surface computes, how to read the score, and where to wire it into a send path.

Every surface below is **advisory and read-only**. None of them sends, routes, blocks, or modifies any outbound message — outbound traffic exits only through the Devotel softswitch, exactly as before. The platform computes the verdict; the decision to act on it — allow, review, or refuse a send — is always the tenant's.

## 1. What SMS-pumping actually looks like

A pumping attack inflates your SMS spend in two recognisable shapes:

* **Premium-rate / IRSF destinations.** Traffic drifts to numbers on revenue-share ranges (historically Cuba, Somalia, Sierra Leone-class corridors). Each accepted message bills at several times a normal rate.
* **OTP-completion collapse on Verify.** Bots request real SMS OTPs but never enter a code. Verify's per-destination conversion (verified ÷ sent) falls far below your tenant baseline while carrier spend keeps accruing.

Both shapes are detectable from signals your tenant already accrues: destination-prefix prefixes, send velocity, delivery conversion, geographic spread, and — for Verify — OTP completion rates. The three surfaces below package those signals into scores you can query and act on.

## 2. The three surfaces

| Surface                      | Endpoint                             | What it computes                                                                                                                                                                                                                            |
| ---------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Composite risk verdict**   | `POST /api/v1/risk/score`            | Fuses every anti-fraud detector into one 0-100 verdict — the SMS-pumping score (always), an outbound URL/link-reputation score (when a message body is supplied), plus optional pass-through Verify Fraud Guard and Voice Biometrics scores |
| **Artificial-traffic score** | `POST /api/v1/messages/risk-signals` | The per-destination SMS-pumping score on its own, with a transparent per-factor breakdown (destination-prefix patterns, recent send velocity, delivery conversion, 24h geo-spread, outbound blocklist)                                      |
| **Verify AIT analytics**     | `GET /api/v1/verify/fraud-analytics` | Aggregated metrics from the persisted fraud-event ledger: blocked + step-up totals, per-channel and per-reason breakdowns, a per-day series, and estimated blocked spend saved                                                              |

A fourth Verify-specific detector, `GET /api/v1/verify/conversion-anomaly`, flags destinations whose OTP completion rate is far below your tenant baseline and reports the estimated spend at risk — run it periodically as the detection side of the same posture.

## 3. Reading the score

All scoring surfaces return the same three top-level fields:

* **`score`** — a composite risk score from **0** (clean) to **100** (certain block).
* **`band`** — a coarse label derived from the score: below 25 `low`, 25+ `elevated`, 50+ `high`, 80+ `critical`.
* **`recommendation`** — the mapped advisory action: `allow`, `review`, or `block`.

The same cut-offs apply in both the standalone SMS-pumping scorer and the composite verdict, so a `high` band means the same thing on `POST /messages/risk-signals` and on `POST /risk/score`.

The composite verdict also returns a **per-channel breakdown** — `sms_pumping`, `url_reputation`, `verify_fraud`, `voice_biometrics` — naming which detector(s) fired and their individual scores. The composite is the **maximum of the present channels** (worst present channel), chosen deliberately: a message that `review`s on any single channel gets flagged rather than averaged back to `low`, and a destination with no signal at all returns a clean score of 0 rather than a misleading average.

The standalone SMS-pumping score returns a **`factors`** array instead — one entry per signal that contributed, with a machine-readable `code`, the `points` it added, and a human-readable `detail`. The per-factor breakdown sums (before the 100 cap) into the composite score, so the verdict is never a black box.

## 4. Advisory, not enforcing

<Warning>
  These surfaces score; they do not enforce. `POST /risk/score`, `POST /messages/risk-signals`, and the Verify analytics endpoints never send, route, block, or modify an outbound message. The Devotel softswitch remains the sole outbound path for every channel. Whether a given score means "send anyway", "queue for review", or "refuse the destination" is a decision your own campaign or send code makes. The `recommendation` field is a suggested action — nothing more.
</Warning>

Tenants that want the platform's built-in enforcement layer on top can configure **Fraud Shield** on the messaging side (`GET` / `PUT /api/v1/messages/fraud-shield`, then `POST /api/v1/messages/fraud-shield/evaluate` to turn a score into a terminal allow/review/block decision against your own thresholds and country lists) and the **Fraud Guard** on the Verify side (which can refuse an OTP pre-send). Those are separate, tenant-owned configurations; this guide covers only the always-on scoring surfaces.

## 5. Worked examples

### Composite verdict: `POST /api/v1/risk/score`

Query the fused verdict for a destination before a send. Supply `channel` so the correct velocity aggregate drives the SMS-pumping leg, and optionally the message body so URLs inside it are reputation-scanned.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/risk/score" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "+15550199",
    "channel": "sms",
    "message_body": "Your code is 384216. Reply STOP to opt out."
  }'
```

A flagged response looks like:

```json theme={null}
{
  "score": 85,
  "band": "critical",
  "recommendation": "block",
  "channels": [
    { "channel": "sms_pumping", "score": 85, "present": true, "reasons": ["high_risk_prefix"] },
    { "channel": "url_reputation", "score": 0, "present": false, "reasons": [] }
  ]
}
```

If you already run a Verify Fraud Guard evaluation or a Voice Biometrics challenge for this session, pass their scores through as `verify_signal` / `voice_biometrics_signal` so the composite folds them into the same verdict instead of you reconciling four independently-banded results.

### Per-factor breakdown: `POST /api/v1/messages/risk-signals`

When the composite flags a destination, the standalone scorer tells you exactly which signals fired:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/messages/risk-signals" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"destination": "+15550199", "channel": "sms"}'
```

```json theme={null}
{
  "score": 90,
  "band": "critical",
  "recommendation": "block",
  "factors": [
    { "code": "test_range", "points": 90, "detail": "NANP +1 555-NXX reserved fictional / test range" }
  ]
}
```

Each factor is an additive weight capped at 100 in total: tenant outbound blocklist (100), NANP +1 555-NXX test range (90), known IRSF / premium-rate prefix (85), send-velocity spike (up to 40, ratio-scaled against your velocity window), 24h geo-spread anomaly (25), low delivery-conversion rate (up to 30, only when at least 20 terminal sends back the rate), and cross-tenant corridor reputation (up to 35, only once a pumping corridor is corroborated across at least 3 distinct tenants). A missing signal — for example, no delivery history yet — contributes *nothing* rather than inventing or absolving risk. The corridor-reputation factor is the platform's shared cross-tenant feed; the [shared fraud-reputation concept page](/concepts/network-signals-fraud-reputation) explains what it records and why it needs multi-tenant corroboration.

### Historical posture: `GET /api/v1/verify/fraud-analytics`

Aggregate what the fraud-event ledger already caught over a window (1–90 days, default 30):

```bash theme={null}
curl -X GET "https://api.orbit.devotel.io/api/v1/verify/fraud-analytics?window_days=30" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

The response carries blocked and step-up totals, per-channel and per-reason breakdowns, a per-day time series for charting, and an estimated blocked-spend-saved figure. Pair it with `GET /api/v1/verify/conversion-anomaly` (same `window_days` query) to see *unblocked* AIT suspects — destinations converting far below your baseline — and download `GET /api/v1/verify/conversion-anomaly/evidence-export.csv` when you need an RFC-4180 evidence pack for a carrier chargeback dispute.

## 6. Webhooks and the fraud-event ledger

Two streams make the posture observable after the fact:

* **`verification.fraud_blocked`** — emitted when the pre-send Fraud Guard refuses an OTP send. The payload carries the channel, destination, the computed `risk_score`, and the machine-readable `fraud_reasons` (for example `["risk_block", "roaming"]`). Pre-send refusals are deliberately *not* reported as `verification.failed` — no verification row exists, so there is no phantom failure. See the [webhook events reference](/reference/webhook-events) for the full payload shape and the companion `verification.fraud_step_up` event.
* **The fraud-event ledger** — every block and step-up verdict persists to a per-tenant ledger. `GET /api/v1/verify/fraud-analytics` (above) is the reporting surface over it: per-channel and per-reason totals, a per-day series, and the cumulative estimated spend saved by the blocked events.

## 7. Wire it into the send path

Query before committing spend, not after. The cheapest integration point is the campaign or send orchestration code that already validates a recipient:

```bash theme={null}
# 1. Score the destination
SCORE=$(curl -s -X POST "https://api.orbit.devotel.io/api/v1/risk/score" \
  -H "X-API-Key: $ORBIT_API_KEY" -H "Content-Type: application/json" \
  -d '{"destination": "+15550199", "channel": "sms"}')

# 2. Apply YOUR policy to the advisory verdict
BAND=$(echo "$SCORE" | jq -r '.band')
case "$BAND" in
  low|elevated) ;;             # proceed
  high)        #route to manual review queue
    ;;
  critical)    #refuse the send for this recipient
    ;;
esac
```

The composite endpoint is rate-limited to 120 requests/minute per tenant, so for high-volume campaign sends score the campaign's distinct destination *prefixes* first and only escalate full destination-level checks on suspicious prefixes. Cache verdicts by destination for the duration of a campaign — a destination's score does not change meaningfully inside a send window.

For ongoing hygiene, schedule `GET /api/v1/verify/fraud-analytics` daily and `GET /api/v1/verify/conversion-anomaly` weekly; when the anomaly report flags a new destination, feed it back into your send-side policy (or your outbound blocklist, which the scorer itself reads) so the next send to that destination scores `critical` immediately.

## What's next

* [Shared cross-tenant fraud reputation](/concepts/network-signals-fraud-reputation) — how the anonymized corridor-reputation feed works and why it needs 3-tenant corroboration.
* [Risk API reference](/api-reference/endpoints/risk) — full parameter and response schema for the composite verdict.
* [Messaging API reference](/api-reference/endpoints/messaging) — the `risk-signals` scorer, Fraud Shield configuration, and the `evaluate` decision endpoint.
* [Verify API reference](/api-reference/endpoints/verify) — `conversion-anomaly`, `fraud-analytics`, and the evidence-export CSV.
* [Webhook events reference](/reference/webhook-events) — `verification.fraud_blocked` payload and the pre-send-block error contract.
