> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fluz.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limits

> Fluz applies protective, per-service rate limits to keep the platform stable. What the limits are, what a 429 looks like, and how to build clients that stay within them.

Fluz doesn't sell per-plan API quotas — there are no "Free = X req/min, Pro = Y req/min" tiers and no per-key quota system. Instead, each service applies a **protective rate limit** to absorb abuse and shield its backend. Normal interactive and application traffic effectively never hits these limits; they exist to catch runaway scripts and abuse.

<Info>
  There are no published per-plan quotas to request an increase against. If a well-behaved integration is hitting limits, that usually points to a traffic pattern worth fixing (see [Build a well-behaved client](#build-a-well-behaved-client)) rather than a quota to raise.
</Info>

## How limits are applied

Limits are enforced independently **per service** and are evaluated globally across that service's instances — you can't escape a limit by landing on a different server. A request is identified by a combination of:

* **Your IP address** — every request counts against a per-IP limit.
* **Your access token** — the full `Authorization` header. Requests with no auth header skip the token limiter but still count against the IP limiter, so send a stable token to be limited as *you* rather than lumped in with everyone sharing an IP.
* **The endpoint path** — on some public surfaces, specific paths have their own limits.

Exceeding any limit returns **HTTP `429 Too Many Requests`**.

## Traffic limits by surface

These are sustained per-second limits. When exceeded, the key is blocked for a short cooldown before requests are accepted again.

| Surface                                                                | Limit                                   | Cooldown after exceeding |
| ---------------------------------------------------------------------- | --------------------------------------- | ------------------------ |
| **GraphQL API** — the transactional graph endpoint (`/api/v1/graphql`) | 20 requests / second                    | 10 seconds               |
| **Gift card vendor operations**                                        | 20 requests / second                    | 10 seconds               |
| **Social graph** (contacts, invites, follows)                          | 50 requests / second                    | 10 seconds               |
| **Other services** (default)                                           | 10 requests / second                    | next request rejected    |
| **Mobile / app gateway**                                               | Protective limits tuned per environment | —                        |

<Note>
  The GraphQL API endpoint is the one most integrations call for deposits, purchases, transfers, and reveals — plan around **20 requests per second** there. The mobile/app gateway's per-IP, per-token, and per-endpoint limits are configured per environment and aren't published as fixed numbers; treat them as protective and back off on `429`.
</Note>

## Authentication & security

Sign-in, PIN, and two-factor (2FA) flows are protected separately from general API traffic. Repeated failed attempts — logins, PIN checks, or 2FA verification — and excessive 2FA or SMS requests trigger temporary lockouts that clear on their own after a cooldown. Successful authentication resets these counters.

<Warning>
  Don't auto-retry failed logins, PIN checks, or 2FA. Surface a "try again later" state to the user — automatic retries extend the lockout.
</Warning>

## When you exceed a limit

Every rate-limited response uses status **`429 Too Many Requests`**. The body and headers vary by surface:

<CodeGroup>
  ```json GraphQL / web / vendor services theme={null}
  {
    "message": "Rate limit exceeded"
  }
  ```

  ```json Gateway / auth services (standardized error) theme={null}
  {
    "success": false,
    "msg": "Too many requests, please try again later",
    "errorRecord": {
      "code": "G-0002",
      "name": "RatelimitExceeded"
    }
  }
  ```
</CodeGroup>

Header availability is not uniform:

* **`Retry-After`** (integer seconds) is returned on the authentication IP limiter and the PIN/2FA flows. It is **not** guaranteed on the general GraphQL/web traffic limiters.
* There are currently **no** `X-RateLimit-Limit`, `X-RateLimit-Remaining`, or `X-RateLimit-Reset` headers — don't build logic that depends on them.

## Build a well-behaved client

<Steps>
  <Step title="Treat 429 as retryable">
    Honor `Retry-After` when it's present. When it isn't, back off exponentially starting around 1 second (1s → 2s → 4s…) rather than retrying immediately.
  </Step>

  <Step title="Keep sustained rates modest">
    Don't parallel-blast a surface from a single IP or token. For the GraphQL API, stay comfortably under 20 requests/second and smooth out bursts.
  </Step>

  <Step title="Don't auto-retry auth failures">
    Repeated login, PIN, or 2FA failures cause temporary lockouts. Show the user a "try again later" message instead of retrying automatically.
  </Step>

  <Step title="Send a stable access token">
    Authenticate every request with your token so token-based limits apply to your traffic specifically, instead of being aggregated with others behind a shared IP.
  </Step>
</Steps>

Because `Retry-After` isn't guaranteed everywhere, pair your retry logic with [idempotency keys](/concepts/idempotency) so a retried mutation never double-processes a purchase or transfer. For the full error catalog, see [Errors](/api-reference/errors).
