---
title: "Release a held message — by the agent-safety verdict or by an inbound policy (a human decides)"
method: POST
path: "/inbound/{uid}/release"
tags: ["Inbound"]
---

# Release a held message — by the agent-safety verdict or by an inbound policy (a human decides)

`POST /inbound/{uid}/release`

## Request

- Base URL: `https://api.oveyon.com/v1`
- URL: `https://api.oveyon.com/v1/inbound/{uid}/release`
- Auth: HTTP bearer

Dispatches now, to the mailbox channels (respecting a restrict_channels the policy recorded — if it would leave a recipient without channels it is dropped, with the tag `would_restrict_channels:<name>`), a message that was held at arrival — with the verdict and `message.quarantine` (heldAt, releasedAt, releasedBy) in the payload. Scope write:inbound: release is an operator gesture, never a tool of the model (the key that replies does not release). Records who released (`api:<key prefix>`). Without a body it releases EVERY held copy; `{ "recipient": "<mailbox>" }` releases only the copy of that mailbox (each recipient is held by its own mailbox choices and policies).

## Path parameters

- `uid` string, required

## Request body

- object
  - `recipient` string: Release only the copy of this mailbox (one of `recipients[].to`).

## Response `200`

Released

- InboundReleaseResult
  - `id` string, uuid
  - `status` 'released'
  - `deliveries` integer: How many channel deliveries were queued now. 0 with noChannel=true means the mailbox has no active channel — the message stays readable in the panel and the API.
  - `noChannel` boolean
  - `releasedAt` string, date-time
  - `releasedBy` string
  - `recipients` string[]: The mailboxes whose copies this call released.
  - `stillHeld` integer: Copies of the message still held after this call (releasing one recipient of several).

## Other responses

- `400`: bad_recipient
- `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.
- `404`: Does not exist, belongs to another account, or the identifier is malformed — the response is identical in all three cases, on purpose.
- `409`: not_quarantined — no copy of the message is held; recipient_not_quarantined — the copy of that mailbox is not held
- `410`: copy_expired — the archived copy is gone; nothing can be dispatched
- `413`: payload_too_large — the request body exceeds this route's limit (`limit`, in bytes: 25 MB unless the operation says otherwise). The key is validated before the body is read: without a valid key the answer is 401/403 and the body is not read. Do not retry the same body.
- `415`: unsupported_media_type — send the body as `application/json` (form and plain-text bodies are not accepted).
- `422`: no_mailbox, or recipient_not_in_message — the message was not sent to that mailbox
- `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)
