BetterFans Link: the OnlyFans APIBetterFans Link

Rate limits

Limits are per key. Read the RateLimit headers, and on 429 wait for Retry-After.

Each key has its own limit. One busy key never slows down another key in the same workspace.

The limits

KeyRequests per secondBurst
bfl_live_ and bfl_test_ keys2060
MCP clients connected with OAuth1030

The limit works like a bucket that holds up to the burst and refills at the steady rate. A key that has been idle can send the whole burst at once, then settles to the per second rate.

Who am I returns your key's limit in rateLimit, so your code can read it instead of hard coding it.

Headers

Every response carries the key's current budget.

HeaderMeaning
RateLimit-LimitThe most requests the key can make in a burst.
RateLimit-RemainingRequests left right now.
RateLimit-ResetSeconds until the bucket is full again.

When you hit the limit

Over the limit, the request fails with 429 rate_limited and a Retry-After header in seconds. Wait that long, then retry. Nothing ran, so retrying is safe for every route.

async function call(url: string, init: RequestInit = {}, tries = 3): Promise<Response> {
  const res = await fetch(url, init);
  if (res.status === 429 && tries > 1) {
    const wait = Number(res.headers.get("Retry-After") ?? "1");
    await new Promise((r) => setTimeout(r, wait * 1000));
    return call(url, init, tries - 1);
  }
  return res;
}

Staying under it

  • Page with limit=100 instead of many small pages.
  • Cache what does not change often, such as the account list and fan lists.
  • Prefer webhooks to polling. message.received and transaction.created tell you when there is something new.
  • Use fresh=true only when you need a live answer. Live reads are slower, so a loop of them holds your budget longer.
  • Run large jobs with a small, fixed number of requests in flight instead of firing them all at once.

On this page