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

# Rate limits

> Per-principal read/write budgets, login throttles, lockout rules, and how to handle 429s.

Limits are generous for real integrations and tight enough to blunt abuse.

## The numbers

| Scope                              | Limit                             | Window                   |
| ---------------------------------- | --------------------------------- | ------------------------ |
| Login attempts                     | 10                                | 15 minutes per IP        |
| Write requests (POST/PATCH/DELETE) | 30                                | 1 minute per principal   |
| Read requests (GET)                | 120                               | 1 minute per principal   |
| Account lockout                    | after 5 consecutive failed logins | 15 minutes               |
| Faucet volume                      | deployment-configured cap         | rolling 24 h per account |

A **principal** is whoever authenticated: a given API key and a browser
session count separately, but all keys of one account share its account-level
protections.

## When you exceed a limit

The API returns `429` with the standard envelope:

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Try again shortly."
  }
}
```

Back off and retry. A simple pattern with jitter:

```bash theme={null}
attempt=0
until out=$(curl -sf "$BASE/balances" -H "Authorization: Bearer $KEY"); do
  attempt=$((attempt+1))
  [ $attempt -ge 5 ] && { echo "giving up" >&2; exit 1; }
  sleep $(( (2 ** attempt) + RANDOM % 3 ))
done
echo "$out"
```

## Staying well under the limits

* **Poll gas, not balances.** `GET /gas` is designed for polling; `/balances`
  does FHE work. See [Balances](/concepts/balances).
* **Poll transactions at 3–10 s intervals**; faster adds no information
  (Sepolia blocks land every \~12 s) and burns read budget.
  See [Track transactions](/guides/track-transactions).
* **Paginate deliberately.** `pageSize` goes up to 100; one big page beats
  five small ones.
* **Money movement already blocks up to \~90 s** waiting for receipts, so don't
  wrap it in a hot retry loop; on `PENDING`, switch to polling the
  transaction.

## Lockout behavior

Five consecutive failed logins lock the account for 15 minutes; even correct
credentials are refused until the window passes. Failed-attempt counters reset
on successful login. Locked-out or disabled states are not distinguishable
from bad credentials in the login response (deliberately), so surface the
generic failure to end users.
