> ## 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.

# Anomaly detection — reading usage & delivery anomalies across Insights

> Read the Usage anomalies ledger and the alert surfaces across Insights — what the detectors observe, where anomalies surface in the dashboard, and how to work a spike end to end.

# Anomaly detection — reading usage & delivery anomalies across Insights

Orbit runs automatic detectors against your own account traffic that flag behaviour deviating from its normal pattern — a spend spike, a toll-fraud attempt, a SIM-swap on your verification traffic, an API key calling home from an unexpected country. Every detection lands in a single append-only ledger. This guide shows you where anomalies surface across Insights, how to read the ledger, and what to do about what you find.

If you are looking for the rule-authoring workflow instead (threshold and anomaly rules you define yourself), see [Usage & delivery anomaly alert rules](/guides/usage-anomaly-alert-rules). This page covers the platform's **own** detectors — which fire with no configuration at all.

## What gets observed

Every detection creates one ledger entry with a **category**, a **severity**, a **status**, and a **scope**. It is classified into one of two scopes:

* **Wallet** — anomalies on the spend-bearing channels: SMS, WhatsApp, email, RCS, voice, AI agents, or an "all channels" roll-up. This is your money-side scope. An alert here means usage or spend on a paid channel behaved abnormally.
* **Webhook** — anomalies tied to inbound traffic and webhook delivery: phone numbers, webhook endpoint delivery. Inbound anomalies rarely cost you money directly; they signal probing or abuse pointed at your numbers.

The detector categories you will see in the ledger:

| Category                  | What the detector watches                                                                                                         |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Spend spike               | The rate your wallet drains accelerates beyond its pattern — both in USD and in message throughput.                               |
| Toll-fraud (IRSF) blocked | Outbound calls or messages aimed at premium-rate destination numbers — the classic revenue-share pumping scheme.                  |
| Suspicious campaign send  | A campaign whose send shape deviates from its history (sudden volume, unusual correlation signals).                               |
| SIM swap detected         | Verification traffic whose carrier records show the destination SIM was recently swapped — attacks on one-time-password delivery. |
| Voice deepfake            | Voice traffic scored as likely synthetic or manipulated audio.                                                                    |
| API key location anomaly  | An API key authenticating from a geography inconsistent with its usage history.                                                   |
| SMS pumping blocked       | Artificial SMS traffic inflation on your verification endpoints, including controls that push back on abusers.                    |

Severity ranks **low → medium → high → critical**: `high` and `critical` demand same-day action; everything else queues for review.

The ledger is **read-only automatic detection**. Entries are still acknowledged and triaged from the Fraud alerts card on your Insights overview; [Usage & delivery anomaly alert rules](/guides/usage-anomaly-alert-rules) is where you add your own threshold-and-anomaly rules on top (delivery rate, outbound volume, spend) with notifications you control.

## Surfaces consuming anomaly detection

Four places in the dashboard read anomaly detection:

1. **Insights → Usage anomalies** (`/insights/anomalies`) — the forensics surface this guide walks through: per-scope totals, a per-day trendline, and the raw ledger table.
2. **Insights → overview Fraud alerts card** (`/insights`) — your live open alerts with the acknowledge/triage controls. This is where an anomaly gets **worked**; the anomalies page is where it gets **read**.
3. **Insights → Usage alert rules and KPI Alerts** — the self-serve layer. Rules you author post their breach notifications to the [Notification Center](/guides/in-dashboard-notifications), not into the detector ledger.
4. **Fired-alert deep links** — when one of your alert rules fires, its notification deep-links into the Insights page, so the detour from notification to the ledger view is one click.

All three ledger endpoints are tenant-scoped and return the standard `{ "data": ..., "meta": ... }` envelope:

| Method | Path                                    | Purpose                                                                                                             |
| ------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/insights/anomaly-insights/by-scope`   | Per-scope totals over the window: total, open count, high-or-critical count, latest detection time.                 |
| `GET`  | `/insights/anomaly-insights/timeseries` | Zero-filled per-day buckets per scope — the trendline. Days with no detections appear as `0`, not as a missing day. |
| `GET`  | `/insights/anomaly-insights/history`    | The raw ledger rows, newest first, paged at up to 100 entries per request.                                          |

All three accept a `days` window (default 30, maximum 365) or an explicit `from`/`to` ISO datetime pair, plus `scope=wallet|webhook`; `/history` additionally takes `limit`.

## Reading the Usage anomalies page

Open **Insights → Usage anomalies**. Three components answer three questions, in this order:

1. **The summary strip** — *is anything wrong right now?* Per scope (`wallet`, `webhook`) you get the window total, the open count, the high-or-critical count, and the latest detection timestamp, plus the all-scopes total. Start here: a healthy account shows zero open and zero high/critical in both scopes.
2. **The per-day trendline** — *is this a blip or a pattern?* The chart stacks wallet against webhook per UTC day. A single tall spike with empty days either side is usually one campaign or one attack burst; a rising staircase is a sustained shift — misconfiguration or ongoing abuse.
3. **The ledger table** — *which entries exactly?* Every detection, newest first, with category, severity, status, scope, channel, and detection time, paged at up to 100 rows per request. Entries carry only scrubbed fields a tenant should see — provider-internal payloads never render.

Scope the whole page with the wallet / webhook filter, and widen the window with `days` or `from`/`to` when you need more than the default 30 days.

## Worked example: a spend spike end to end

A runtime monitoring pulse goes off overnight. Here is the operator pass, top to bottom:

1. **Summary strip:** wallet scope shows `total: 6`, `open: 2`, `high_or_critical: 1`; webhook scope is flat at zero. The problem is on a spend-bearing channel, not inbound.
2. **Trendline:** wallet buckets hold at 0–1 per day for three weeks, then jump to 6 on a single day. A burst, not a drift — something happened on that day.
3. **Ledger table:** the day's entries read **Spend spike** (severity `high`, channel `sms`) and **Toll-fraud (IRSF) blocked** (severity `critical`). The toll-fraud detector already blocked the worst of it; the spend-spike entry quantifies what got through before the block engaged.
4. **Act on it in place:** switch to the **Insights → overview** Fraud alerts card to acknowledge the critical entry so the rest of the team sees it is being handled.
5. **Prevent the repeat:** open **Insights → Usage alert rules** and add a threshold rule — for example `spend`, `comparator: gt`, `threshold: 100`, `window_days: 1`, with [in-app notification](/guides/usage-anomaly-alert-rules) — so the next overnight spike pages the team at \$100 instead of after the fact.

## API usage

Same pass over the API — wallet scope, last 7 days:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/insights/anomaly-insights/by-scope?days=7" \
  -H "Authorization: Bearer dv_live_sk_…"
```

```json theme={null}
{
  "data": {
    "window": { "from": "2026-08-22T00:00:00.000Z", "to": "2026-08-29T00:00:00.000Z", "days": 7 },
    "scopes": [
      { "scope": "wallet", "total": 6, "open_count": 2, "high_or_critical_count": 1, "latest_detected_at": "2026-08-28T03:14:00.000Z" },
      { "scope": "webhook", "total": 0, "open_count": 0, "high_or_critical_count": 0, "latest_detected_at": null },
      6
    ],
    "all_total": 6,
    "truncated": null
  }
}
```

Then the trendline and the rows behind it:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/insights/anomaly-insights/timeseries?days=7&scope=wallet" \
  -H "Authorization: Bearer dv_live_sk_…"
```

```json theme={null}
{
  "data": {
    "window": { "from": "…", "to": "…", "days": 7 },
    "scope": "wallet",
    "buckets": [
      { "day": "2026-08-22", "scope": "wallet", "total": 0 },
      { "day": "2026-08-23", "scope": "wallet", "total": 0 },
      { "day": "2026-08-28", "scope": "wallet", "total": 6 }
    ],
    "truncated": null
  }
}
```

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/insights/anomaly-insights/history?days=7&scope=wallet&limit=10" \
  -H "Authorization: Bearer dv_live_sk_…"
```

```json theme={null}
{
  "data": {
    "window": { "from": "…", "to": "…", "days": 7 },
    "scope": "wallet",
    "items": [
      {
        "id": "…",
        "category": "irsf_blocked",
        "severity": "critical",
        "status": "open",
        "scope": "wallet",
        "source": "toll_fraud_guard",
        "summary": "Premium-rate destination blocked before billable connect.",
        "channel": "sms",
        "detected_at": "2026-08-28T03:14:00.000Z",
        "triaged_at": null,
        "resolved_at": null,
        "details": { "destination": "+44…", "reason": "premium_rate_prefix" }
      }
    ],
    "total": 6
  }
}
```

If `truncated` is non-`null`, the window held more ledger rows than the bounded scan reads — narrow the window or page `/history` instead of relying on the by-scope totals for that window.

## Scopes and access

* Ledger endpoints require an API key or JWT with the analytics read scope — the same posture as the other Insights read surfaces.
* The **Insights → Usage anomalies** page is open to any member who can read Insights; risk and spend visibility should not be gated to finance roles.
* Acknowledge / dismiss / resolve actions from the Fraud alerts card follow your team's compliance permissioning, as on the anti-fraud surfaces.

## Troubleshooting

**The page is empty but you expected alerts.**
Widen the window above the default 30 days, and clear the scope filter back to all scopes. Detectors only write an entry when behaviour actually deviates — a quiet ledger on a healthy account is the correct state, not a broken one.

**A category you do not recognize appears.**
Categories ship ahead of their labels occasionally; the ledger falls back to a Title Case rendering of the detector name. The `irsf_blocked` and `spend_velocity_anomaly` categories have dedicated glossary explainers linked from the dashboard card ("Learn more").

**By-scope total disagrees with your own count.**
You are counting a different window: `by-scope` and `timeseries` always resolve either `days` or an explicit `from`/`to` into UTC days. Pass the same window to `/history` and compare against `data.total`.

**An alert fired but nothing is in the ledger.**
Your own [alert rules](/guides/usage-anomaly-alert-rules) fire to the Notification Center — they are a separate system from the automatic detectors and never write to the anomaly ledger.

## See also

* [Usage & delivery anomaly alert rules](/guides/usage-anomaly-alert-rules) — author your own threshold and anomaly rules on delivery rate, volume, and spend
* [In-dashboard notifications and the Notification Center](/guides/in-dashboard-notifications) — where fired rules page your team
* [SMS pumping protection](/guides/sms-pumping-protection) — the controls behind the SMS-pumping detector category
* [Insights dashboards](/guides/insights-dashboards) — the hub walkthrough for every Insights surface
