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

# Alerts

> Platform alerts, unified alert inbox, custom alert rules, multi-channel delivery to Slack and email, and per-event delivery tracking for vessel monitoring.

Platform alerts for sanctions matches, river level warnings, dark fleet events, and more. The alert system includes a unified cross-product inbox, a rule engine for custom filtering, multi-channel notifications, and a delivery audit trail.

## `GET` `/api/v1/alerts`

<Note>Requires API key.</Note>

Get active platform alerts. Filter by severity or type.

**Parameters**

| Name             | Type   | Required | Description                                    |
| ---------------- | ------ | -------- | ---------------------------------------------- |
| `severity`       | string |          | `critical`, `warning`, or `info`               |
| `type`           | string |          | `sanctions_match`, `river_level`, `dark_fleet` |
| `unacknowledged` | string |          | `true` to only show unread alerts              |
| `cursor`         | string |          | ISO timestamp for cursor pagination            |
| `limit`          | number |          | Default 20, capped by your access tier         |

**Response**

```json theme={null}
{
  "alerts": [...],
  "count": 12,
  "unacknowledged": 3,
  "tier": "pro",
  "pagination": { "limit": 20, "has_more": true, "next_cursor": "2026-04-17T08:00:00Z" }
}
```

**Example**

```bash theme={null}
curl -H "X-API-Key: YOUR_KEY" \
  https://axiomoverwatch.io/api/v1/alerts?severity=critical
```

## `GET` `/api/v1/alerts/unified`

<Note>Requires API key.</Note>

Unified cross-product inbox combining maritime and Locus alerts in a single chronological feed. Aggregates platform alerts, dark events, spoofing detections, and Locus score-change alerts.

**Parameters**

| Name        | Type   | Required | Description                                            |
| ----------- | ------ | -------- | ------------------------------------------------------ |
| `product`   | string |          | `all` (default), `overwatch`, or `locus`               |
| `severity`  | string |          | `critical`, `warning`, or `info`                       |
| `watchlist` | string |          | `true` to only include watched vessels                 |
| `portfolio` | string |          | Locus portfolio id filter                              |
| `state`     | string |          | `all` (default), `open`, `read`, `resolved`, `snoozed` |
| `cursor`    | string |          | ISO timestamp for cursor pagination                    |
| `limit`     | number |          | Default 25, max 100                                    |

**Response**

```json theme={null}
{
  "alerts": [
    {
      "id": "dark_event:456",
      "source": "dark_event",
      "product": "overwatch",
      "severity": "critical",
      "title": "AIS gap detected — MV Meridian",
      "description": "Signal lost for 18 hours in Gulf of Guinea",
      "occurred_at": "2026-04-18T03:22:00Z",
      "state": "open",
      "metadata": { "imo_number": "9622629", "gap_hours": 18 }
    }
  ],
  "count": 1,
  "pagination": { "limit": 25, "has_more": false, "next_cursor": null },
  "filters": { "product": "all", "severity": null, "watchlist": false, "portfolio": null, "state": "all" }
}
```

**Example**

```bash theme={null}
curl -H "X-API-Key: YOUR_KEY" \
  https://axiomoverwatch.io/api/v1/alerts/unified?product=overwatch&state=open
```

## `POST` `/api/v1/alerts/unified/state`

<Note>Requires API key.</Note>

Set per-user state for a unified alert—mark it as read, resolved, snoozed, or reopen it.

**Parameters**

| Name           | Type   | Required | Description                                            |
| -------------- | ------ | -------- | ------------------------------------------------------ |
| `alert_id`     | string | ✓        | Alert id in `source:id` format (e.g. `dark_event:456`) |
| `action`       | string | ✓        | `read`, `resolve`, `snooze`, or `open`                 |
| `snooze_until` | string |          | ISO timestamp; defaults to +24 hours for snooze        |

**Response**

```json theme={null}
{
  "ok": true,
  "alert_id": "dark_event:456",
  "action": "resolve",
  "state": { "read_at": "2026-04-18T10:00:00Z", "resolved_at": "2026-04-18T10:00:00Z", "snoozed_until": null }
}
```

**Example**

```bash theme={null}
curl -X POST -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  https://axiomoverwatch.io/api/v1/alerts/unified/state \
  -d '{"alert_id": "dark_event:456", "action": "resolve"}'
```

***

## Alert rules

Define custom rules that filter the unified alert stream using boolean expressions. Rules support nested `and`/`or` groups and can match on product, severity, event type, vessel IMO, or any metadata field. Every rule change is versioned so you can audit who changed what and when.

### `GET` `/api/v1/alerts/rules`

<Note>Requires API key.</Note>

List your alert rules.

**Response**

```json theme={null}
{
  "rules": [
    {
      "id": 1,
      "name": "Critical dark events",
      "description": "Flag critical AIS gaps on watchlisted tankers",
      "expression": {
        "kind": "group",
        "operator": "and",
        "conditions": [
          { "kind": "condition", "field": "severity", "op": "eq", "value": "critical" },
          { "kind": "condition", "field": "source", "op": "eq", "value": "dark_event" }
        ]
      },
      "severity_override": null,
      "active": true,
      "dedupe_window_minutes": 60,
      "version": 3,
      "created_at": "2026-04-10T09:00:00Z",
      "updated_at": "2026-04-18T14:30:00Z"
    }
  ]
}
```

**Example**

```bash theme={null}
curl -H "X-API-Key: YOUR_KEY" \
  https://axiomoverwatch.io/api/v1/alerts/rules
```

### `POST` `/api/v1/alerts/rules`

<Note>Requires API key.</Note>

Create a new alert rule.

**Parameters**

| Name                    | Type    | Required | Description                                                        |
| ----------------------- | ------- | -------- | ------------------------------------------------------------------ |
| `name`                  | string  | ✓        | Rule name                                                          |
| `description`           | string  |          | Human-readable description                                         |
| `expression`            | object  | ✓        | Boolean expression tree (see below)                                |
| `severity_override`     | string  |          | Override the alert's severity when this rule matches               |
| `dedupe_window_minutes` | number  |          | Suppress duplicate matches within this window (1–1440, default 60) |
| `active`                | boolean |          | Whether the rule is active (default `true`)                        |

#### Expression format

Expressions are recursive trees of groups and conditions:

```json theme={null}
{
  "kind": "group",
  "operator": "and",
  "conditions": [
    { "kind": "condition", "field": "product", "op": "eq", "value": "overwatch" },
    {
      "kind": "group",
      "operator": "or",
      "conditions": [
        { "kind": "condition", "field": "source", "op": "eq", "value": "dark_event" },
        { "kind": "condition", "field": "source", "op": "eq", "value": "spoofing_alert" }
      ]
    }
  ]
}
```

**Supported condition fields**

| Field        | Description                                                        |
| ------------ | ------------------------------------------------------------------ |
| `product`    | `overwatch` or `locus`                                             |
| `severity`   | `critical`, `warning`, or `info`                                   |
| `source`     | `platform`, `dark_event`, `spoofing_alert`, `locus_alert`          |
| `event_type` | Alert event type string                                            |
| `entity_id`  | Entity identifier                                                  |
| `imo_number` | 7-digit IMO number                                                 |
| `metadata.*` | Any key in the alert's metadata object (e.g. `metadata.gap_hours`) |

**Supported operators:** `eq`, `neq`, `in`, `contains`, `gte`, `lte`

**Example**

```bash theme={null}
curl -X POST -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  https://axiomoverwatch.io/api/v1/alerts/rules \
  -d '{
    "name": "Critical dark events",
    "expression": {
      "kind": "group",
      "operator": "and",
      "conditions": [
        { "kind": "condition", "field": "severity", "op": "eq", "value": "critical" },
        { "kind": "condition", "field": "source", "op": "eq", "value": "dark_event" }
      ]
    },
    "dedupe_window_minutes": 120
  }'
```

### `PATCH` `/api/v1/alerts/rules`

<Note>Requires API key.</Note>

Update an existing rule. Changes are versioned—pass an optional `notes` field to record why the change was made.

**Parameters**

| Name         | Type    | Required | Description                |
| ------------ | ------- | -------- | -------------------------- |
| `id`         | number  | ✓        | Rule id                    |
| `name`       | string  |          | Updated name               |
| `expression` | object  |          | Updated expression         |
| `active`     | boolean |          | Enable or disable the rule |
| `notes`      | string  |          | Version history note       |

**Example**

```bash theme={null}
curl -X PATCH -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  https://axiomoverwatch.io/api/v1/alerts/rules \
  -d '{"id": 1, "active": false, "notes": "Pausing during port maintenance window"}'
```

### `DELETE` `/api/v1/alerts/rules`

<Note>Requires API key.</Note>

Delete a rule.

**Parameters**

| Name | Type   | Required | Description           |
| ---- | ------ | -------- | --------------------- |
| `id` | number | ✓        | Rule id (query param) |

**Example**

```bash theme={null}
curl -X DELETE -H "X-API-Key: YOUR_KEY" \
  "https://axiomoverwatch.io/api/v1/alerts/rules?id=1"
```

### `POST` `/api/v1/alerts/rules/dry-run`

<Note>Requires API key.</Note>

Test a rule expression against recent alerts without saving it. Use this to preview how many alerts a rule would match before creating it.

**Parameters**

| Name            | Type    | Required | Description                                 |
| --------------- | ------- | -------- | ------------------------------------------- |
| `expression`    | object  | ✓        | Rule expression to test                     |
| `product`       | string  |          | `all` (default), `overwatch`, or `locus`    |
| `severity`      | string  |          | Filter by severity before evaluation        |
| `watchlistOnly` | boolean |          | Only test against watchlisted vessel alerts |
| `portfolioId`   | string  |          | Scope to a Locus portfolio                  |
| `limit`         | number  |          | Max alerts to evaluate (1–200, default 100) |

**Response**

```json theme={null}
{
  "evaluated": 87,
  "matched": 12,
  "alerts": [...]
}
```

**Example**

```bash theme={null}
curl -X POST -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  https://axiomoverwatch.io/api/v1/alerts/rules/dry-run \
  -d '{
    "expression": {
      "kind": "group",
      "operator": "and",
      "conditions": [
        { "kind": "condition", "field": "severity", "op": "eq", "value": "critical" },
        { "kind": "condition", "field": "source", "op": "in", "value": ["dark_event", "spoofing_alert"] }
      ]
    },
    "product": "overwatch"
  }'
```

***

## Alert channels

Configure where alert notifications are delivered. You can enable multiple channels simultaneously—each channel is independently toggled and tested.

**Supported channels:** Slack, Microsoft Teams, email, and custom webhook.

### `GET` `/api/v1/alerts/channels`

<Note>Requires API key.</Note>

List your configured alert channels. Secrets and webhook URLs are partially masked in the response.

**Response**

```json theme={null}
{
  "channels": [
    {
      "channel": "slack",
      "enabled": true,
      "config": { "webhook_url": "https://hooks.slack.com/services/T00.../B00.../xxxx" }
    },
    {
      "channel": "webhook",
      "enabled": true,
      "config": { "url": "https://example.com/hooks/axiom", "secret": "****" }
    }
  ]
}
```

**Example**

```bash theme={null}
curl -H "X-API-Key: YOUR_KEY" \
  https://axiomoverwatch.io/api/v1/alerts/channels
```

### `PUT` `/api/v1/alerts/channels`

<Note>Requires API key.</Note>

Create or update a channel configuration.

**Parameters**

| Name      | Type    | Required | Description                                |
| --------- | ------- | -------- | ------------------------------------------ |
| `channel` | string  | ✓        | `slack`, `email`, `teams`, or `webhook`    |
| `enabled` | boolean | ✓        | Whether the channel is active              |
| `config`  | object  | ✓        | Channel-specific configuration (see below) |

**Channel configuration**

| Channel   | Config fields                                                                                             |
| --------- | --------------------------------------------------------------------------------------------------------- |
| `slack`   | `webhook_url` — must be a `https://hooks.slack.com/services/...` URL                                      |
| `teams`   | `webhook_url` — any valid HTTPS URL                                                                       |
| `email`   | `to` — comma-separated email addresses                                                                    |
| `webhook` | `url` — HTTPS endpoint; `secret` (optional) — HMAC-SHA256 signing key, sent as `X-Axiom-Signature` header |

**Example**

```bash theme={null}
curl -X PUT -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  https://axiomoverwatch.io/api/v1/alerts/channels \
  -d '{
    "channel": "slack",
    "enabled": true,
    "config": { "webhook_url": "https://hooks.slack.com/services/T00.../B00.../xxxx" }
  }'
```

### `DELETE` `/api/v1/alerts/channels`

<Note>Requires API key.</Note>

Remove a channel configuration.

**Parameters**

| Name      | Type   | Required | Description                     |
| --------- | ------ | -------- | ------------------------------- |
| `channel` | string | ✓        | Channel to remove (query param) |

**Example**

```bash theme={null}
curl -X DELETE -H "X-API-Key: YOUR_KEY" \
  "https://axiomoverwatch.io/api/v1/alerts/channels?channel=teams"
```

### `POST` `/api/v1/alerts/channels/test`

<Note>Requires API key.</Note>

Send a test notification through a configured channel. The test message uses sample vessel data so you can verify formatting and delivery.

**Parameters**

| Name      | Type   | Required | Description                             |
| --------- | ------ | -------- | --------------------------------------- |
| `channel` | string | ✓        | `slack`, `email`, `teams`, or `webhook` |

**Example**

```bash theme={null}
curl -X POST -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  https://axiomoverwatch.io/api/v1/alerts/channels/test \
  -d '{"channel": "slack"}'
```

***

## Alert deliveries

Track the status of every alert notification sent through your configured channels. The delivery ledger records each attempt, retries with exponential backoff, and moves permanently failed deliveries to a dead-letter queue.

### `GET` `/api/v1/alerts/deliveries`

<Note>Requires API key.</Note>

List recent alert deliveries and any dead-lettered failures.

**Parameters**

| Name      | Type   | Required | Description               |
| --------- | ------ | -------- | ------------------------- |
| `channel` | string |          | Filter by channel type    |
| `status`  | string |          | Filter by delivery status |
| `limit`   | number |          | Default 50, max 200       |

**Response**

```json theme={null}
{
  "deliveries": [
    {
      "id": 42,
      "channel": "slack",
      "event_key": "dark_event:456",
      "event_type": "dark_event",
      "status": "delivered",
      "attempts": 1,
      "delivered_at": "2026-04-18T03:23:01Z",
      "last_error": null,
      "created_at": "2026-04-18T03:22:58Z"
    }
  ],
  "dead_letters": [],
  "count": 1
}
```

**Example**

```bash theme={null}
curl -H "X-API-Key: YOUR_KEY" \
  https://axiomoverwatch.io/api/v1/alerts/deliveries?channel=slack
```
