Skip to main content
The API allows 200 requests per minute for each user your app acts for, counted per OAuth client, and returns 429 with a Retry-After header when the budget is spent. Plan against it before you launch, and check the rules below when you start seeing 429 responses.
Don’t poll chat endpoints for new messages. Polling is the main cause of 429 responses. Subscribe to webhooks for new events and pull deltas in bulk with Efficient chat sync.

How the budget works

The default limit is a budget of 200 points per 60 seconds. Each request spends one point, and the budget refills to full at the end of the window. It’s counted per OAuth client per user, so each user who authorises your app has their own budget and one user’s traffic never affects another’s. Agencies can be granted higher limits on request. A higher limit is shared by the whole agency team as one budget per OAuth client, rather than one per team member. Read X-RateLimit-Limit on the response rather than assuming 200. The count is global per identity. Spreading traffic across servers, processes or IP addresses does not multiply the budget, because every request decrements the same counter.

How the bucket is keyed

Routes under /creators/{creatorUserUuid}/... key the budget on the creator as well, so each creator you act for has a separate 200-point budget. Every other route, including the aggregate /agencies/* endpoints, draws from the single budget of the calling user. Use the creator-scoped routes for high-volume per-creator work and keep the shared budget for cross-creator queries.

Capacity planning

Re-polling chats for new messages is the most common cause of throttling. Polling every chat on a fixed interval scales with creators × chats × poll frequency, and most of those requests return nothing new. Two paths cost less:
  1. Use webhooks instead of polling. Subscribe to creator.message.received and creator.message.read and let Fanvue push events to you. Steady-state request cost is zero.
  2. When you must pull, pull deltas. Call POST /chats/messages/batch with a sinceMessageUuid cursor to fetch only what changed across up to 50 chats in one request.
Efficient chat sync covers both with a worked request budget. When you estimate headroom for a growing creator count, remember how the bucket is keyed. Creator-scoped routes each have their own 200-point budget, so per-creator work scales with the number of creators. Aggregate /agencies/* calls share one budget, so reserve it for cross-creator queries.

Headers

Every rate-limited response carries the limit headers, not only a 429, so you can slow down before you hit zero. API conventions lists them alongside the other headers every endpoint shares. A request over the budget returns:

Per-endpoint limits

A few endpoints carry their own limit, with its own counter, fixed regardless of agency limits. The /v1/chats/lists/dynamic/* routes and POST /v1/webhooks/test spend a point on both their own counter and the 200-point budget. The other routes in the table carry only their explicit limit. Dynamic list limits are keyed on the user alone, so one person calling through several apps draws on one counter. Each dynamic list route and its /v1/creators/{creatorUserUuid}/chats/lists/dynamic/... twin share a counter. X-RateLimit-Limit reports the limit that fired, so a 429 from a dynamic list route shows the route’s own cap rather than 200.

Concurrency and deep pages

At most 6 requests per caller may be in flight at once, where a caller is one OAuth client acting for one user. A seventh request is rejected straight away with 429, Retry-After: 1 and the body { "error": "Too many concurrent requests" }. A slot frees as soon as an in-flight request settles, so a client that retries after 1 second proceeds. This response carries no X-RateLimit-* headers, so branch on the error string to tell it from a spent budget; Error responses shows both 429 bodies. On previous-version list endpoints that page with page and size, a deep page costs more than one point. Pages 1 to 25 cost 1 point. Beyond that, a request costs ceil(page / 25) points, capped at 20, so page 150 costs 6 points. A request that carries the route’s cursor parameter, such as beforeMessageUuid on chat messages, costs 1 point whatever page says. Cursor pagination on /v1 always costs 1 point per request. See Moving to v1.

Handle 429 in code

Wait the number of seconds in Retry-After, then retry. A minimal retry wrapper:
Read X-RateLimit-Remaining on every response and slow down before it reaches zero, rather than waiting for a 429.