Skip to main content
Every endpoint on the previous, unversioned Fanvue API follows the conventions below. You call these paths when you maintain an integration built before /v1, or when you need an endpoint that has no /v1 form; new work belongs on the current version. Every request needs an access token and the version header, and Build your first app gets you a first authenticated call if you haven’t made one. The API speaks JSON over HTTPS. Paths on this version carry no prefix:
A chat list is GET https://api.fanvue.com/chats, called exactly as written. The current version adds the /v1 prefix and answers on https://api.fanvue.com/v1/chats. The OpenAPI 3.1 document for this version is served at /openapi.json for client generators and request tools.

Authentication

Every endpoint requires a Bearer access token obtained through the OAuth 2.0 flow. Send it on every request.
A missing or expired token returns 401. A token that lacks the scope an endpoint needs returns 403 with { "error": "Insufficient scopes" }. The authentication overview explains how your app obtains a token, and Scopes lists what each scope unlocks.

API versioning

Always send the X-Fanvue-API-Version header. The current version is 2025-06-26.
The header is a date string that pins the response contract. A request without the header is served as 2025-06-26. A value the API does not recognise returns 400 with { "error": "Unsupported API version", "message": "..." }. A sunset version returns 410 with a nextVersion field naming the version to move to. The URL prefix (/v1/ or none) is a separate axis that selects the current or previous resource shapes. See API versioning.
Some endpoints live only on this version. App Store endpoints (/apps/*) have no /v1 form, and neither do the self-scoped /account-health and /account-health/flagged-media. Call those on the unversioned paths even from a /v1 integration.

Pagination

List endpoints on this version use one of two styles. Both wrap their items in a top-level data array.
Send the page-size parameter the endpoint declares. The API ignores the other name and returns the default page size. Page-based lists take size. Lists that page by cursor take limit, except the insights lists, /agencies/insights/demographics and both tracking-link impressions lists, which take size.
Most lists on this version page with a 1-based page number and a size, and return a pagination object.The envelope is data plus pagination with page, size and hasMore. Increment page while hasMore is true. A page above 25 costs more than one rate-limit point; see Concurrency and deep pages.
/checkout-links, /collections, /media-links, /creators/{creatorUserUuid}/checkout-links and /creators/{creatorUserUuid}/vault/folders accept page and size even though their reference pages do not list them.
Every list on /v1 is cursor-based. Moving to v1 shows how to convert a paging loop.

Error responses

Errors use HTTP status codes with a JSON body. There is no single error envelope. The body shape depends on the status and the route family. Error responses lists every body shape the API emits and what to do with each. Batch endpoints return 200 even when some items fail. A failed key carries 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

Each user your app acts for has a budget of 200 requests per 60 seconds, counted per OAuth client. A second 429 body, { "error": "Too many concurrent requests" }, caps in-flight requests at 6 per caller. Rate limits has the per-endpoint limits, the concurrency cap and the retry pattern. Polling list endpoints for new messages or sales is the main cause of 429 responses. Subscribe to webhooks for new events instead, and use Efficient chat sync to catch up after downtime.

Idempotency

Three write endpoints are safe to retry, each in its own way. Pick a new key for every distinct send or charge. A UUID generated when the user confirms the action is a good key: it survives a retry of the same action and never collides with the next one.

Money figures and timestamps

Amounts are integers in minor units, USD cents unless a field says otherwise. Each money-bearing resource carries its own currency field. On earnings rows, gross is the creator’s price the earning is calculated from, net is the creator’s cut after Fanvue fees, and total is what the fan was charged including tax and the fan-side transaction fee. Whether a refunded or charged-back purchase is still counted is decided per field, not per endpoint. A reversal is written as its own row for the full original amount, never as an edit to the payment it reverses, and reversedTransactionOrderId pairs the two. Insights metrics holds the payment-source table and the field-by-field reversal reference. Timestamps are UTC in ISO 8601 format. Date-range query parameters such as startDate and endDate accept an ISO 8601 datetime with or without a timezone offset, and statistics aggregate 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. The underlying instant is UTC in both cases.

Agency creator scoping

Agency team members act on a managed creator through the creator-scoped twin of each endpoint under /creators/{creatorUserUuid}/.... A twin takes the same body, returns the same shape and needs the same scopes as the self-serve route, plus access to that creator. The creator-scoped routes are the high-volume path for agencies: each creator has its own rate-limit bucket on them. Agency-wide list endpoints under /agencies/* cover every creator the agency manages in one response. Every row carries a creatorUuid field naming the creator it belongs to, so you can group rows without a second lookup. Pass creatorUuids, a comma-separated list of up to 50 creator UUIDs, to narrow the response. A creatorUuids value that does not belong to the agency fails the whole request with 403. The /agencies/* endpoints need read:agency on top of the data scope, and read:agency is grantable by agency admins only.