v1, the current URL version, you send requests to:
v1 endpoint carries the prefix, so a chat list is GET https://api.fanvue.com/v1/chats. The previous version drops it and answers on https://api.fanvue.com/chats instead. See API versioning below.
This page documents the conventions that apply across every v1 endpoint: how to authenticate, how to pin an API version, how paginated responses are shaped, what error bodies look like, how rate limiting is signalled, and how idempotency, timestamps and agency scoping work. Use the navigation to browse endpoints by resource, or try requests directly from each endpoint page.
Authentication
All endpoints require a Bearer access token obtained via the OAuth 2.0 flow. See the Authentication guide to set up an OAuth application and obtain tokens.401 or 403. See Error responses below.
API versioning
Every request must send theX-Fanvue-API-Version header. The version is a date string, and the current version is 2025-06-26.
/v1 prefix on a path is a separate version axis. It selects the shape of the endpoint: which query parameters it takes and how a list paginates. /v1 is the current URL version; the unversioned paths are the previous one. Use the version selector in the top bar to move this reference between v1 and v0. See Moving to v1 for the endpoint-by-endpoint mapping.
Not everything has a /v1 form
App Store endpoints (/apps/*) exist only on the unversioned paths, so call them without a prefix even from a v1 integration. The self-scoped /account-health and /account-health/flagged-media are also unversioned only; their creator-scoped counterparts do have a v1 form at /v1/creators/{creatorUserUuid}/account-health.Pagination
Everyv1 list endpoint is cursor-based. You pass an opaque cursor and a page-size parameter, and the response returns a nextCursor to fetch the following page. Every list wraps its results in a top-level data array, so you always read items from data.
The response envelope returns
data plus a nextCursor. When nextCursor is null, you have reached the end of the collection. Some lists also carry a total, which is null when no count was computed for that list, so treat it as an optional hint rather than something to page against.
cursor set to the previous nextCursor until nextCursor is null:
Page-based pagination, with
page and hasMore, belongs to the previous version. No v1 endpoint accepts a page parameter. See Moving to v1 for how to convert a paging loop.Error responses
Errors use standard HTTP status codes. The response body is JSON, but its exact shape depends on the kind of error. There is no single global error envelope: validation errors return anerrors array, while most other errors return a single error or message string. For the recovery action to take on each error, and which are safe to retry, see Errors.
Some endpoints define additional, more specific
400 variants documented on the endpoint page itself:
Endpoint-specific 400 variants
Endpoint-specific 400 variants
ValidationError({ "errors": ["..."] }): one or more request fields failed validation.InvalidUuidError({ "message": "..." }): a UUID path or body parameter is not a valid UUID.ContactabilityError({ "message": "..." }): the target user cannot be contacted (for example messaging restrictions).MessageValidationError({ "message": "..." }): message-specific validation failed, such as media ownership or content checks.
Batch endpoints return
200 even when some items fail. Inside the 200 body, individual keys that could not be resolved carry a PerKeyError with error set to forbidden, not_found or internal, so a batch keeps its partial results instead of failing the whole request.Rate limit headers
By default each user can make 200 requests per 60 seconds. See Rate Limits for the full policy. Rate-limited responses (429) include the following headers, defined in the spec’s RateLimitResponse:
When you receive a
429, wait Retry-After seconds (or until X-RateLimit-Reset) before sending the next request.
Idempotency
The grant endpoint,POST /v1/media/{uuid}/grant, is idempotent by design. It grants a consumer access to a media item, and repeated calls with the same parameters return the existing entitlement rather than creating a duplicate.
Idempotency is keyed on the source and sourceRef fields you supply in the request body:
The same
source + sourceRef pair always resolves to the same entitlement, so you can safely retry a grant after a network failure without double-granting.
entitlementId and status: "granted" whether the entitlement was just created or already existed, so a retry is indistinguishable from the first successful call. Granting media requires the write:media scope.
Money figures
All amounts are integers in minor units (USD cents unless a field says otherwise). Two conventions sit behind the wordsgross and net, and insights endpoints do not treat refunds and chargebacks the same way as each other:
grossis what the fan paid,netis the creator’s cut after platform fees.- Whether a refunded or charged-back purchase is still counted is decided per field, not per endpoint. On
GET /v1/insights/fans/{userUuid}for example,spending.totalis net of reversals whilespending.sourcesare gross of them, so the sources do not sum to the total.
GET /v1/insights/earnings, reversedTransactionOrderId pairs the reversal with the original.
See Insights Metrics for the payment-source table, the field-by-field gross and net reference, and how often each figure is recomputed.
Timestamps
All timestamps are UTC and formatted as ISO 8601 datetime strings. Date-range query parameters (such asstartDate and endDate on insights endpoints) accept an ISO 8601 datetime, with or without a timezone offset, and stats are aggregated by UTC day.
Some response fields use a date-only format (
date) and others a full datetime (date-time); each field documents its own format on the endpoint page. Regardless of format, the underlying instant is UTC.Agency creator scoping
Agency-scoped list endpoints under/v1/agencies/* cover every creator an agency manages in a single response. So that consumers can group rows by creator without a second lookup, every row is tagged with the creator it belongs to via a creatorUuid field.
This applies across the agency endpoints, for example:
GET /v1/agencies/earnings: each earnings row carriescreatorUuid(the agency-managed creator the earnings row belongs to).GET /v1/agencies/subscribers: each subscriber carriescreatorUuid(the creator they are subscribed to).GET /v1/agencies/chats: each chat carriescreatorUuid(the creator that owns the chat).GET /v1/agencies/subscribers-history: each history row carriescreatorUuid.
creatorUuids query parameter, a comma-separated list of creator UUIDs (max 50):
creatorUuid, consumers can group or attribute results client-side without joining against a separate creators list.