> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Every Fanvue API error: status code, body shape, and the recovery action to take. Which errors to retry, which to fix, and which to surface to the user.

Errors use standard HTTP status codes with JSON bodies. There is no single global envelope: validation errors return an `errors` array; most other errors return a single `error` or `message` string. This page lists every error and **what to do about it**.

## Errors and recovery actions

| Status        | Error                       | Body shape                                                            | Recovery action                                                                                                                                                                                                         |
| ------------- | --------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`         | `UnsupportedVersionError`   | `{ "error", "message" }`                                              | Send a valid `X-Fanvue-API-Version` header (current: `2025-06-26`). Don't retry unchanged.                                                                                                                              |
| `400`         | `ValidationError`           | `{ "errors": ["..."] }`                                               | Fix the listed fields. Don't retry unchanged.                                                                                                                                                                           |
| `400`         | `InvalidUuidError`          | `{ "message" }`                                                       | A path or body UUID is malformed. Fix the identifier.                                                                                                                                                                   |
| `400`         | `ContactabilityError`       | `{ "message" }`                                                       | The target user can't be contacted (messaging restrictions). Skip this recipient; don't retry.                                                                                                                          |
| `400`         | `MessageValidationError`    | `{ "message" }`                                                       | Message-specific validation failed (media ownership, content checks). Fix the message payload.                                                                                                                          |
| `401`         | Unauthorized                | `{ "error" }`                                                         | Access token missing, invalid or expired. [Refresh the token](/docs/authentication/implementation-guide), then retry **once**. If refresh fails, re-authorize the user.                                                      |
| `403`         | Forbidden (scope)           | `{ "error" }`                                                         | The token lacks a scope or permission. Add the [scope](/docs/authentication/scopes) in the Builder **and** request it in your OAuth flow, then have the user reconnect. Don't retry unchanged.                               |
| `403`         | `age_verification_required` | `{ "error", "message", "ageVerificationUrl" }`                        | Media endpoints only, in regions requiring age verification. Send the user to `ageVerificationUrl`; retry after they verify. See [Working with Media](/docs/tutorials/working-with-media#age-verification-for-media-access). |
| `404`         | Not found                   | `{ "message" }`                                                       | The resource or a referenced UUID doesn't exist. For vault folders, `{folderName}` is the exact display name, case-sensitive and URL-encoded, not an id. Don't retry unchanged.                                         |
| `409`         | Conflict                    | `{ "message" }`                                                       | A uniquely named resource (list, collection, vault folder) already exists. Reuse the existing resource or pick a new name.                                                                                              |
| `410`         | `SunsetVersionResponse`     | `{ "error", "message", "nextVersion" }`                               | The API version is retired. Move to `nextVersion`.                                                                                                                                                                      |
| `429`         | Rate limited                | `{ "error" }` + [headers](/docs/api-reference/overview#rate-limit-headers) | Wait `Retry-After` seconds (or until `X-RateLimit-Reset`), then retry. See [Rate Limits](/docs/authentication/rate-limits).                                                                                                  |
| `502` / `503` | Upstream unavailable        | No defined body                                                       | Transient. Retry with exponential backoff and jitter.                                                                                                                                                                   |

## Retry rules

| Retry?                               | Statuses                                                                         |
| ------------------------------------ | -------------------------------------------------------------------------------- |
| **Yes, after waiting**               | `429` (wait `Retry-After`), `502`/`503` (exponential backoff + jitter)           |
| **Once, after refreshing the token** | `401`                                                                            |
| **Never unchanged**                  | `400`, `403`, `404`, `409`, `410`, fix the request, permission, or version first |

A `403` from a media read endpoint may be `age_verification_required` rather than a scope problem: branch on the `error` field before treating it as a permissions failure.

## Partial failures on batch endpoints

Batch endpoints return `200` even when some items fail. Failed keys carry a `PerKeyError` with `error` set to `forbidden`, `not_found` or `internal`, so the batch keeps its partial results. Treat `internal` as retryable for that key; `forbidden` and `not_found` as terminal.

## Payment failures

Failed charges are reported on webhooks, not API errors: [`app.payment.failed`](/docs/app-store/webhooks/payments) and [`checkout_link.payment.failed`](/docs/checkout/payments) carry a decline `reason`, see [Failure reasons](/docs/checkout/payments#failure-reasons) for the values and what to do about each. Failed renewals are retried by Fanvue's own dunning; don't build your own retry loop on top.

## See also

* [API conventions](/docs/api-reference/overview): base URL, versioning, pagination, timestamps.
* [Rate Limits](/docs/authentication/rate-limits): the full policy behind `429`.
* [Delivery, Retries and Idempotency](/docs/webhooks/delivery-and-idempotency): the webhook-side counterpart to this page.
