400 | { "errors": [{ "code", "message" }] } or { "errors": ["..."] } | Request validation failed. Route validation returns objects with a code and a message such as Invalid size: must be number, got string. Pagination validation on page and size returns plain strings. | Handle both shapes: treat each entry as an object when it has a message field, otherwise as a string. Fix the named fields. Do not retry unchanged. |
400 | { "error": "Unsupported API version", "message" } | The X-Fanvue-API-Version value is not recognised. | Send 2025-06-26. See API versioning. |
400 | { "message" } | One of three route errors. InvalidUuidError: a UUID path or body parameter is malformed. ContactabilityError: the target user cannot be contacted. MessageValidationError: media ownership or content checks failed. | Fix the identifier or payload. For a contactability error, skip the recipient. |
400 | { "error": "USER_NOT_ALLOWED" }, { "error": "manager-invite-creator.invitation-already-sent" }, { "error": "manager-invite-creator.team-member-already-agency-manager" } or { "error": "manager-invite-creator.team-member-account-not-found" } | An agency invite was refused. USER_NOT_ALLOWED: the address is banned, belongs to a creator account, or the caller lacks team-management permission. invitation-already-sent: the address already holds a seat or a pending invite. team-member-already-agency-manager: the address manages another agency. team-member-account-not-found: no Fanvue account exists for the address. | Show the reason to the inviter. For team-member-account-not-found, ask the invitee to sign up first. |
400 | { "message" } | On POST /experiences/{experienceUuid}/action-purchases, the Idempotency-Key header is missing. On experience publish and update routes, the platform refused a field such as an access mode the experience type does not allow. | Add the header, or remove the refused field. |
401 | { "error": "Unauthorized" } | The access token is missing, malformed or expired. It can also belong to a user whose account is no longer active, or who ended their sessions after the token was issued. | Refresh the token and retry once. If the refresh fails with invalid_grant, or the retry returns 401 again, stop and send the user through authorisation again. Do not retry in a loop. See the implementation guide. |
402 | { "error", "message", "balance", "amount" } | On POST /experiences/{experienceUuid}/action-purchases, the fan’s wallet balance does not cover the action. balance is what the fan holds and amount is the price, both in USD cents. Nothing was charged. | Send the fan to the in-experience top-up, then retry with a new Idempotency-Key. |
403 | { "error": "Insufficient scopes" } | The token lacks a scope the endpoint needs. | Add the scope on the Authentication tab or in oauth.scopes. Request it in your authorisation URL, then have the user reconnect. See Scopes. |
403 | { "message": "Forbidden" } | The experience or launch token does not belong to the calling app. On creator-scoped routes, the caller cannot act for this creator. | Check the experience belongs to your app. Check the user has access to the creator. Do not retry unchanged. |
403 | { "error": "consent_required", "message" } | On an action purchase, the fan has given no spend consent for this experience. | Send the fan through the in-experience top-up, which records consent, then retry. |
403 | { "error": "payer_ineligible", "message" } | On an action purchase, the fan cannot be charged. Causes: account not active, payments blocked, blocked by the creator, or required age verification not passed. | Show the fan the message. Do not retry until their status changes. |
403 | { "error": "app_not_installed", "message" }, { "error": "app_not_available", "message" }, or a third error value returned when fan experience publishing is not enabled for the creator | On experience publish routes. app_not_installed: the creator has not installed your app. app_not_available: your app is not available to them. The third value: the creator’s account does not have fan experience publishing enabled. | Ask the creator to install the app from the App Store, or wait for availability. Do not retry unchanged. |
403 | { "error": "FEATURE_NOT_ENABLED", "message" } or { "error": "TAX_BEHAVIOR_NOT_ENABLED", "message" } | On POST /checkout-links: checkout links are not enabled for this creator, or the creator cannot set taxBehavior yet. The field is refused rather than coerced. | Omit taxBehavior, or ask the creator to enable checkout links. |
403 | { "error" } on a /lists/dynamic route | The account does not have the dynamic list builder enabled. The error string varies. | Treat the account as not eligible. Dynamic lists are available to creators who have the dynamic list builder enabled. |
403 | { "error": "age_verification_required", "message", "ageVerificationUrl" } | A media read in a region that requires age verification. | Send the user to ageVerificationUrl, then retry after they verify. See Work with media. |
404 | { "message": "Resource not found" } | A path or body UUID references an object that does not exist, or the caller cannot see it. For vault folders, {folderName} is the exact display name, URL-encoded, not an id. | Check the identifier. Do not retry unchanged. |
404 | { "message": "App not found" } | On GET /apps/{appUuid}/subscription/me, the app is not visible to this non-agency user. A user with no subscription record receives 200 with status: "none" instead. | Treat the app as not visible to the user, not as unsubscribed. Check appUuid. See Subscription status. |
409 | { "message" } | A uniquely named resource such as a list, collection or vault folder already exists. | Reuse the existing resource or pick a new name. |
409 | { "message" } | An Idempotency-Key conflict. Either the first request with this key is still running, or the key was already used for a different payload. | Still running: wait, then replay with the same key. Reused: pick a fresh key for the new payload. See the idempotency rules. |
409 | { "error": "paid_impact_acknowledgement_required", "message", "impact" } | An experience update or unpublish would affect fans who paid. impact carries affectedFanCount, activeSubscriptionCount, pendingSubscriptionInvoiceCount, oneTimePurchaseCount and pendingPurchaseCount. | Show the creator the impact, then retry with the acknowledgement flag set. See Publish an experience. |
409 | { "error": "blocked_active_subscriptions", "message", "impact" } | An experience change is blocked while fans hold active subscriptions to it. | Wait for the subscriptions to end, or change only fields that do not affect paying fans. |
410 | { "error": "API version no longer supported", "message", "nextVersion" } | The date version has passed its sunset. | Move your header to nextVersion. |
413 | { "message" } | A multipart upload part number is beyond the maximum number of parts for the maximum file size. | Reduce the file size or part count. See Upload media in parts. |
429 | { "error": "Too many requests" } with X-RateLimit-* and Retry-After | The per-minute budget or a per-endpoint limit is spent. | Wait Retry-After seconds, then retry. See Rate limits. |
429 | { "error": "Too many concurrent requests" } with Retry-After: 1 | More than 6 requests from the same caller are in flight. No X-RateLimit-* headers. | Wait 1 second and retry. Cap your client’s concurrency at 6 per user. |
502 | { "message" } | An /apps or /experiences route’s upstream returned an error, was unreachable or timed out. No Retry-After header. | Retry with exponential backoff and jitter, capped at a few attempts, then surface the error. On POST /experiences/{experienceUuid}/action-purchases, replay with the same Idempotency-Key or read the purchase back first: the charge may have settled upstream. |
503 | { "error": "Service Unavailable" } with Retry-After: 5 or Retry-After: 15 | A database statement timed out (5) or a database connection timed out (15). | Wait Retry-After seconds, then retry. |
503 | { "message" } | An /apps or /experiences route’s upstream is not configured, or wallet charges are not available for this experience. No Retry-After header. | Do not retry quickly: an unconfigured upstream clears only when the environment is fixed. If the message names wallet charges, treat the experience as unable to take action purchases. |