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

# Alerts & anomalies

> Webhook and Slack alerts on metric thresholds, plus automatic anomaly detection.

Orbitrage notifies you when a metric crosses a threshold you set, or when its detectors spot an anomaly on their own. Both deliver to a webhook URL or to Slack.

## Threshold alerts

Create an alert from the **Customise** page or by asking [Ask Analytics](/platform/ask-analytics) (`create_alert`). An alert watches one metric over a sliding window and fires when it crosses your threshold.

<ParamField path="metric" type="string" required>
  One of `calls_count`, `cost_total`, `savings_total`, `tokens_in`,
  `tokens_out`, `tokens_total`, `errors_count`, `tool_calls_count`,
  `unique_users`, `unique_models`, `avg_latency_ms`, `p95_latency_ms`.
</ParamField>

<ParamField path="threshold_op" type="string" required>
  Comparison: `>`, `<`, `>=`, or `<=`.
</ParamField>

<ParamField path="threshold_value" type="number" required>
  The value to compare against.
</ParamField>

<ParamField path="window_minutes" type="number" default="5">
  Sliding window to evaluate the metric over (1–1440).
</ParamField>

<ParamField path="cooldown_minutes" type="number" default="60">
  Minimum gap between fires (1–10080).
</ParamField>

<ParamField path="webhook_url" type="string" required>
  An `https://` receiver. A `hooks.slack.com` URL is auto-formatted for Slack.
</ParamField>

<ParamField path="filter" type="object">
  Optional scoping by `workflow_id`, `end_user_id`, `model`, `provider`, or
  `tool_name`.
</ParamField>

### Webhook payload

When a non-Slack alert fires, Orbitrage POSTs JSON and signs it:

```json theme={null}
{
  "event": "alert.fired",
  "alert_id": "uuid",
  "alert_name": "cost spike on Prod",
  "org_id": "uuid",
  "metric": "cost_total",
  "threshold": { "op": ">", "value": 50, "window_minutes": 60 },
  "current_value": 61.2,
  "filter": { "workflow_id": "..." },
  "fired_at": "2026-06-07T14:00:00Z"
}
```

The request carries `X-Orbitrage-Signature: <hex>`, an HMAC-SHA256 of the raw body using the alert's **webhook secret** (shown once at creation). Verify it:

```python theme={null}
import hmac, hashlib
def verify(body_bytes, header_hex, secret):
    digest = hmac.new(secret.encode(), body_bytes, hashlib.sha256).hexdigest()
    return hmac.compare_digest(digest, header_hex)
```

<Note>
  Slack webhooks (`hooks.slack.com`) receive Block Kit instead of the signed JSON — the URL itself is the secret, so no signature is added.
</Note>

## Anomaly detection (automatic)

Beyond explicit thresholds, Orbitrage learns each org's normal pattern and alerts on deviations — no configuration beyond a Slack connection.

* Baselines are computed per **hour-of-week** (so 3pm Tuesday is judged against past 3pm Tuesdays), as a rolling mean and standard deviation over `calls`, `cost`, `errors`, and `tokens`.
* Each hour, the just-completed hour is compared to its baseline. If it deviates beyond a Z-threshold (default 3) — and the same metric hasn't already fired this hour — a Block Kit message is posted to your Slack channel.
* Anomalies are skipped when there aren't enough samples yet (minimum 3 for that hour-of-week) or while a cooldown is active.

Same statistical engine as [the Intelligence layer](/concepts/intelligence).

## Delivering to Slack

| Path                    | How                                                                                                                  |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Connected Slack app** | Install from Customise → Slack. Powers proactive anomaly alerts and the [Slack agent](/platform/slack).              |
| **Per-org webhook**     | Paste an incoming-webhook URL at Customise → Slack integration. Used by anomaly alerts and the `send_to_slack` tool. |
| **Per-alert webhook**   | Set any alert's `webhook_url` to a `hooks.slack.com` URL.                                                            |

## Scheduling (self-hosted note)

Alerts and anomaly checks run on a schedule (every minute for threshold alerts; hourly for anomalies) authenticated with a shared `CRON_SECRET`. The managed platform wires this up already; if you self-host, schedule the cron endpoints via `pg_cron` + `pg_net` or any external scheduler.
