---
title: "Appeal a cold-firewall refusal"
method: POST
path: "/v1/messages/appeal"
tags: ["Messages"]
---

# Appeal a cold-firewall refusal

`POST /v1/messages/appeal`

## Request

- Base URL: `https://api.mails.ai`
- URL: `https://api.mails.ai/v1/messages/appeal`
- Auth: HTTP bearer

**Requires scope:** `send`. Requests a second, independent review of content refused with `cold_email_prohibited`. Submit the SAME subject and body the refused send used. An independent reviewer re-judges it under the identical policy: `overturned` clears exactly that content for 24 hours (the identical send then goes through); `upheld` means the refusal stands; `not_appealable` means the block is deterministic policy (prohibited content, bulk list language, multi-signal cold pitches) and no review exists; `not_blocked` means the content is not refused at all. Identical content replays its stored outcome — an appeal is never a re-roll. Limit: 10 appeals per workspace per 24 hours.

## Request body

- object
  - `agent` string: Agent name or id the refused send used. Optional — omitted, the workspace's single agent is assumed (the refused send itself created one if none existed).
  - `subject` string: The refused message's subject, verbatim.
  - `body_text` string: The refused message's body_text, verbatim.
  - `body_html` string: The refused message's body_html, verbatim.

## Response `200`

The review outcome.

- object
  - `outcome` 'overturned' | 'upheld' | 'not_appealable' | 'not_blocked', required: Result of the review: `overturned` (the same subject and body go through for the next 24 hours), `upheld` (the refusal stands), `not_appealable` (a policy block no review can lift) or `not_blocked` (the content is not refused; send it as it is).
  - `message` string, required: Human-readable explanation of the outcome and what to do next.
  - `review_score` number: The second reviewer's cold score (0 = clearly transactional, 1 = clearly cold). Absent for not_appealable/not_blocked.
  - `reason` string: The reviewer's one-line reason, when a review ran.
  - `replayed` boolean: True when this outcome was served from a prior appeal of identical content.

## Other responses

- `400`: Invalid request — malformed JSON or a field failed validation. Also `feature_not_enabled` when this server has a feature switched off (custom domains before they are available).
- `401`: Missing or invalid API key.
- `403`: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
- `404`: Resource not found in this workspace, or the agent a send names is archived (`agent_archived`).
- `429`: Rate or quota limit exceeded. The body's `resets_at` and `retry_after_seconds` say when the request can succeed. A `Retry-After` header is sent only when that is 60 seconds or less; a longer wait (an hourly, daily or monthly cap) sends none, so retry at `resets_at` or raise the limit instead of sleeping.
- `500`: Internal server error.

---

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