---
title: "List inbound policies (IF→THEN on what arrives), in evaluation order"
method: GET
path: "/inbound-policies"
tags: ["Inbound"]
---

# List inbound policies (IF→THEN on what arrives), in evaluation order

`GET /inbound-policies`

## Request

- Base URL: `https://api.oveyon.com/v1`
- URL: `https://api.oveyon.com/v1/inbound-policies`
- Auth: HTTP bearer

Evaluated top to bottom on every received message; `tag` and `notify` annotate and continue, every other action stops the chain. With the platform switch off (`holdEnabled: false`), hold/mute/restrict_channels become the tag `would_<action>:<name>`. Scope read:inbound-policies.

## Response `200`

Policies

- InboundPolicyList
  - `policies` InboundPolicy[]
    - `id` integer
    - `name` string
    - `position` integer: Evaluation order (0 = first).
    - `action` string
    - `actionParams` object, nullable
    - `conditions` InboundPolicyCondition[]
      - `field` 'sender' | 'sender.domain' | 'envelope_sender' | 'recipient' | 'subject' | 'body' | 'attachment.name' | 'attachment.type' | 'attachment.count' | 'size_kb' | 'spam_score' | 'spam_filter.score' | 'agent_safety.score' | 'agent_safety.verdict' | 'dmarc' | 'spf' | 'dkim' | 'listed_link' | 'thread.new' | 'thread.replies' | 'hour' | 'weekday', required
      - `op` 'equals' | 'contains' | 'starts_with' | 'ends_with' | 'matches' | 'regex' | 'in' | 'at_least' | 'at_most', required
      - `value` union, required: String, number, boolean or a list, depending on the field and operator (`spam_filter.score` takes a decimal, e.g. 6.5).
        - string
        - number
        - boolean
        - union[]
          - union
            - string
            - number
    - `mailboxes` object[], nullable: null = every mailbox of the account; a list = only these mailboxes. An EMPTY list means the chosen mailboxes were deleted: the policy judges no mailbox until you edit it.
      - `id` integer
      - `address` string: `local@domain`, or `*@domain` for a catch-all.
    - `paused` boolean: New policies are born PAUSED at the end of the order: nothing changes until you unpause.
    - `pausedAt` string, date-time, nullable
    - `version` integer
    - `readable` boolean: false = the stored policy can no longer be interpreted and is SKIPPED at arrival until fixed.
    - `effectiveActionToday` string, nullable: List only. What it does TODAY: `tag` when hold/mute/restrict_channels degrade (platform switch off, or the held cap reached). null when paused.
    - `degradedReason` 'hold_disabled' | 'hold_limit' | 'null', nullable: Why the action TODAY is a tag: the platform switch is off (hold_disabled) or the policy already holds its cap (hold_limit). null while paused or unreadable (`readable: false`) — such a policy is not evaluated.
    - `matches30d` integer
    - `lastMatchedAt` string, date-time, nullable
    - `heldNow` integer: Messages this policy holds right now (cap 200 per policy).
    - `createdBy` string, nullable
    - `updatedBy` string, nullable
    - `createdAt` string, date-time
    - `updatedAt` string, date-time, nullable
  - `total` integer
  - `max` integer
  - `holdEnabled` boolean: The platform switch. Off: hold, mute and restrict_channels become the tag `would_<action>:<name>`.

## Other responses

- `401`: Missing or invalid API key.
- `403`: Insufficient scope (`insufficient_scope`, with `required` and `have`), a scope the key holds but cannot use while its human-approval lock is on (`scope_blocked_by_approval_lock`, with `required` — approve:holds, write:send-policies, manage:webhooks, write:inbound, write:templates, write:surveys, write:domains, write:contacts), API key switched off by its owner in the panel (`key_disabled` — the key is valid; turn it back on or use another one, do not rotate), sending disabled, account suspended (`account_suspended`) or unknown (`account_unknown`), or the key used from an IP outside its allowed ranges (`ip_not_allowed`, with the `allowed` list — see /v1/credentials/ip-rules). 403 is not a limit: do not retry.
- `429`: Per-key limit (`rate_limited`, 600 requests/min by default per API key — or per MCP OAuth connection —, from any IP), per-IP limit for requests WITHOUT a valid credential (`rate_limited`, 600/min by default), too many unknown or malformed credentials from your address (`too_many_auth_failures`, 20/min by default, counted per IPv4 address or per IPv6 /48; a missing `Authorization`, an expired OAuth token or a disabled key do not count, and anything without the shape of one of our keys counts without being checked; from an address over that limit a valid key still gets through within 120 credential checks/min, and above them every credential not validated in the last 5 minutes gets this 429 until the minute turns) — all checked before the route, on every operation —, account quota (`quota_exceeded` with `window`, `used`, `limit`), warmup cap (`warmup_cap_reached`) or saturation (`queue_full`). Honor `Retry-After` with exponential backoff and jitter.
- `500`: internal_error — an unexpected failure on our side. The detail stays in our logs, never in the body. Retry reads; retry a write only when it is idempotent or carries an idempotency key.
- `503`: ip_rules_unavailable — the IP ranges bound to your key could not be checked right now (caution, not a denial). Retry after `Retry-After` (30 s).

---

[API](https://skmtc.dev/oveyon/apis/oveyon-api.md) · [All operations](https://skmtc.dev/oveyon/apis/oveyon-api/llms.txt) · [OpenAPI document](https://skmtc.dev/oveyon/apis/oveyon-api/revisions/abf64c09d297?raw)
