# Errors

> Every error the Revnu API returns, the JSON body each one carries, and whether to retry, fix the request or re-read the card.

Canonical: https://revnu.com/docs/errors
Last updated: 2026-11-07

Every error is JSON with an `error` field, sent with `Cache-Control: no-store`. Some carry one more field that tells you what to do next.

Some errors also carry a stable `code`, `retryable` and `next` instruction without replacing the original `message`. Billing guards distinguish `payment_required`, `payment_paused` and `card_required`; an invalid retry key is `invalid_request_id`. `retryable: false` means the same request will not succeed unchanged. MCP returns the original readable explanation plus a JSON error block containing the full API body, status, code and any `Retry-After` delay. Error results have `isError: true`; their body is separate from each tool's success schema.

```json
{ "error": "forbidden", "requiredScope": "review:write", "message": "This token doesn't have the review:write scope. ..." }
```

| Status | `error` | Extra fields | What to do |
|---|---|---|---|
| `400` | A sentence naming the problem, such as `limit must be a positive integer` | none | Fix the request. Retrying it unchanged gets the same answer. |
| `401` | `unauthorized` | `message` | No valid token. If the `Authorization` header is missing or isn't `Bearer rvp_...`, fix the header. If the token is unknown or revoked, mint a new one. |
| `402` | `setup_pending` | `message` | The account hasn't started its trial yet. Only `/me` and the setup routes answer. Finish setup with [`GET /setup`](https://revnu.com/docs/setup-status.md). |
| `403` | `forbidden` | `requiredScope`, `message` | The token lacks that scope. Scopes are fixed once a token is minted, so mint a new token that has it. |
| `404` | `not found` | none | The id does not exist or belongs to another account. |
| `404` | `not found` | `message` | No such route under `/api/v1`. The routes are in [`/openapi.json`](https://revnu.com/openapi.json). |
| `404` | `unknown workflow run` | none | `GET /leads?workflowRunId=` named a run that isn't yours. |
| `409` | `invalid_action` | `actions` | The card no longer accepts that verb. Re-render from `actions`. |
| `409` | `use_send` | `message`, `actions` | A Gmail card was sent to `/answer`. Use `POST /review/{id}/send`. |
| `409` | `rejected` | `message` | A settled decision, such as a card that was already handled, a card approved on the dashboard's Review page, or an account paused for payment. Show the `message`. |
| `409` | `paused`, `not_approved`, `schedule_pending`, `schedule_error` | `message` | [Running a workflow](https://revnu.com/docs/workflow-run.md) that is paused, proposed but not approved yet, still being scheduled, or has a schedule Revnu couldn't read. |
| `409` | `this address unsubscribed and cannot be unblocked` | none | The address opted out, so it stays on the block list. |
| `409` | `customer_relationship` | `message` | [Removing a block](https://revnu.com/docs/blocklist-remove.md) that [customer sync](https://revnu.com/docs/customer-sync.md) added. Existing customers stay excluded from cold outreach. |
| `429` | `rate limited` | `Retry-After` header | Wait that many seconds, then retry. |
| `500` | `server misconfigured` | none | A configuration problem on Revnu's side. The same call answers the same way until it's fixed. |
| `503` | `temporarily unavailable` | `Retry-After` header | Infrastructure, not your request. Retry the same call unchanged. |
| `503` | `delivery_pending`, `unavailable` | `message`, `Retry-After` header | Gmail sends only: delivery is still being confirmed, or the mail service is down. Retry the same send. |

## 400: the request is wrong

The message is written to be shown to a developer, so log it. Common ones: `body must be JSON` (the body is not a JSON object), `cursor is not valid` (pass back the `nextCursor` you were given, unmodified), `limit must be a positive integer`, `text required`, `unrecognized status`. Routes that take a body name any field they don't know (`unknown field: …`), so a typo fails loudly instead of being ignored. A workflow too big for one run says how far over it is, for example `steps are too long for one run, about 800 characters over. Shorten some details or split this into two workflows.`

## 401 and 404 look alike on purpose

A card, lead or workflow id from another account is a `404`, exactly as if it did not exist, so a token cannot probe for ids it should not see. An unknown or revoked token is always `401`, never `404`.

## 409: re-read, don't retry

A `409` is a decision, not an outage. Two people, or a person and [scheduled auto-send](https://revnu.com/docs/concepts.md#what-ships-on-its-own), can act on the same card, so a verb that was valid when you listed the queue can be gone a second later:

```json
{ "error": "invalid_action", "actions": ["snooze", "dismiss"] }
```

Draw the card again from `actions` and move on. `rejected` carries a `message` a person can read, for example `This was already handled.`

Some `409`s are about the account, not the card. While a trial is waiting for a card, or an account is paused for a failed payment, agent messages answer `409 rejected` with a message saying how to fix it in the dashboard. LinkedIn invite and message cards and gift cards are approved on the dashboard's Review page, so `approve` on them through the API answers `409`.

## 429 and 503: back off and retry

Both send `Retry-After` in seconds. It is computed from the bucket, so retrying sooner only spends another request. See [Rate Limits](https://revnu.com/docs/rate-limits.md) for the numbers. A `503` means the token could not be checked, the limiter was down for a write, or a delivery answer was lost. Retrying is safe: approving a card that already shipped comes back as a `409`, and agent messages and workflow runs take a `clientRequestId` so a retried call does not happen twice.

## Frequently asked questions

### Is there a machine-readable list of routes and errors?

Yes. [`/openapi.json`](https://revnu.com/openapi.json) describes every route, its scope and the error statuses it can return. Each operation links back to its page here.

### Why did an approve return 409 when the card was pending a moment ago?

Someone else resolved it, or it shipped itself at `autoResolveAt`. The body's `actions` says what the card accepts now; an empty list means it is settled.

### Which errors are safe to retry unchanged?

`429` and `503`, after `Retry-After`. Everything else answers the same way until you change the request or the state behind it.
