# Read the active classification rules for the calling org

`GET /v1/undeliverable/rules`

- Authentication: required (Bearer token)
- Required scope: `undeliverable.view`

Returns the active rule set the /v1/undeliverable surface applies
when classifying recipients (SND-713). Three rules are always-on
(locked, cannot be disabled): permanent_bounce, complaint,
rejected. Three rules are configurable per org, each with an
`events` threshold (N) and `window_days` (M) — an address matches
when ≥ N qualifying events have occurred in a rolling M-day window.

When an address matches multiple rules, the wire `reason` is the
highest-priority match in this order:
permanent_bounce > complaint > rejected > repeated_transient >
undetermined > soft_bounce_accumulation.

Rules are read-only over the public API in v1 — changes are made
through the dashboard (audit-logged, granted to owners + admins
only). Callers should pin against `version` and re-fetch when the
`X-SendOps-Rules-Version` header on /v1/undeliverable changes.

## Example request

```bash
curl 'https://api.sendops.dev/v1/undeliverable/rules' \
  -H "Authorization: Bearer $SENDOPS_API_KEY"
```

## Responses

### 200 — Active rule set

Content type: `application/json`

```json
{
  "profile": "strict",
  "rules": {
    "permanent_bounce": {
      "enabled": true,
      "locked": true,
      "events": 0,
      "window_days": 0
    },
    "complaint": {
      "enabled": true,
      "locked": true,
      "events": 0,
      "window_days": 0
    },
    "rejected": {
      "enabled": true,
      "locked": true,
      "events": 0,
      "window_days": 0
    },
    "repeated_transient": {
      "enabled": true,
      "locked": true,
      "events": 0,
      "window_days": 0
    },
    "undetermined": {
      "enabled": true,
      "locked": true,
      "events": 0,
      "window_days": 0
    },
    "soft_bounce_accumulation": {
      "enabled": true,
      "locked": true,
      "events": 0,
      "window_days": 0
    }
  },
  "version": "string",
  "updated_at": "2026-05-17T20:00:00Z",
  "updated_by": "user@example.com"
}
```

### 401 — Missing, malformed, or unknown API key

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```

### 403 — Key lacks the required scope or plan limit violated

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```

### 429 — Per-org rate limit exceeded

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```

### 500 — Unexpected server-side failure. The `code` is `internal_error`. The
`request_id` field can be quoted to SendOps support to investigate.

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```
