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.
Pagination
List endpoints return results in pages. The API uses two pagination styles depending on the endpoint. Both wrap results in a top-leveldata array, so you always read items from data.
- Cursor-based
- Page-based
Used by high-volume and append-only collections (chat media, insights earnings, spending and subscribers, tracking links). You pass an opaque
The response envelope returns To page through the full set, repeat the request with
cursor and a page-size parameter, and the response returns a nextCursor to fetch the following page.| Query parameter | Type | Notes |
|---|---|---|
cursor | string | Opaque cursor. Omit on the first request. Pass the nextCursor from the previous response to get the next page. |
limit or size | number | Items per page. Range 1-50. Default varies by endpoint (for example 20). The page-size parameter is named limit on chat-media and tracking-link endpoints, and size on insights endpoints. |
data plus a nextCursor. When nextCursor is null, you have reached the end of the collection.cursor set to the previous nextCursor until nextCursor is null: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.
| Status | Meaning | Body shape |
|---|---|---|
400 | Bad request. Either the API version is not supported, or request validation failed. | oneOf an UnsupportedVersionError ({ "error", "message" }) or a ValidationError ({ "errors": ["..."] }). |
401 | Unauthorized. Missing, invalid or expired access token. | { "error": "..." } |
403 | Forbidden. The token is valid but lacks the scope or permission for this resource. | { "error": "..." } |
404 | Not found. The resource (or a referenced UUID) does not exist. | { "message": "..." } |
409 | Conflict. A uniquely named resource already exists (for example a list, collection or vault folder with that name). | { "message": "..." } |
410 | Gone. The requested API version has been sunset. | { "error", "message", "nextVersion" } |
429 | Too many requests. The rate limit was exceeded. See Rate limit headers. | { "error": "..." } |
502 / 503 | Upstream or service unavailable. Transient; retry with backoff. | No defined body; treat as transient and retry. |
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 100 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:
| Header | Description |
|---|---|
X-RateLimit-Limit | The maximum number of requests allowed in the current window. |
X-RateLimit-Remaining | The number of requests remaining in the current window. |
X-RateLimit-Reset | The Unix timestamp, in seconds, when the rate limit window resets. |
Retry-After | The number of seconds to wait before retrying the request. |
429, wait Retry-After seconds (or until X-RateLimit-Reset) before sending the next request.
The spec defines these four headers on the
429 response.Idempotency
The grant endpoint,POST /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:
| Field | Type | Purpose |
|---|---|---|
consumerId | string (uuid) | The consumer to grant access to. |
source | string | Identifier for the granting application or reason. Lowercase, digits and underscores only (^[a-z0-9_]+$), max 100 chars. For example spin_the_wheel_reward. |
sourceRef | string | A unique identifier within the source, used for the idempotency key. Max 255 chars. For example a spin-attempt UUID. |
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.
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/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 /agencies/earnings: each earnings row carriescreatorUuid(the agency-managed creator the earnings row belongs to).GET /agencies/subscribers: each subscriber carriescreatorUuid(the creator they are subscribed to).GET /agencies/chats: each chat carriescreatorUuid(the creator that owns the chat).GET /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.