Getting Started
Rate Limits

Rate Limits

The platform applies rate limiting in two layers:

LayerWhereWhat it protects against
Edge (firewall)Before a request reaches the APIVolumetric abuse, brute force, distributed floods
ApplicationPer endpoint, after authenticationThresholds specific to sensitive operations

The edge layer is the baseline and is tuned per installation. The application layer is limited according to what the operation does — all of them are listed below.

The 429 response

When a limit is exceeded you get the standard error envelope, and the response carries a Retry-After header:

HTTP/1.1 429 Too Many Requests
Retry-After: 47
{
  "status": "failure",
  "code": "RATE_LIMITED",
  "statusCode": 429,
  "requestId": "req_7f3d9c1a4b2e"
}
⚠️

Retry-After is in seconds, and you should honour it. Do not invent your own backoff — the server knows when the window resets and you do not. Retrying sooner only feeds the counter.

Depending on the surface you may see one of three codes: RATE_LIMITED · RATE_LIMIT_EXCEEDED · ACTIVATION_RATE_LIMITED. All carry 429; the distinction is useful when you log them.

Per-endpoint limits

Identity SDK

The window is 60 seconds:

EndpointLimit
analyze30 requests/min
Single event120 requests/min
Batch events (events/batch)20 requests/min
Compatibility check60 requests/min

The batch endpoint's limit is lower because each request carries many records. At volume, use the batch endpoint rather than sending single events — 20 batch requests carry far more events than 120 single ones.

Wallet portal

The authentication surface is limited on both IP and phone number, to resist brute force:

OperationPer IPPer phone
Registration3 / hour3 / 5 min
Login10 / min · 40 / hour5 / min
OTP verification10 / min—
OTP resend5 / hour—

Two axes is deliberate. Limiting on IP alone does not stop an attacker who rotates IPs; limiting on phone alone does not stop someone trying many numbers. Together they close both patterns.

POS terminal activation

The window is 5 minutes:

AxisLimit
Per IP10 attempts
Per serial number5 attempts

The serial-number axis bounds attempts to guess the identity of a valid terminal.

Bank accounts — sync now

The window is 60 seconds:

EndpointLimit
POST /api/v1/bank-connect/accounts/{accountId}/sync6 requests/min per API key

The 429 response carries RATE_LIMITED, the Retry-After header and details.retryAfterSeconds. Read endpoints do not count towards this limit. → Bank Accounts › Limits

Retrying correctly

async function callWithBackoff(fn: () => Promise<Response>) {
  for (let attempt = 0; attempt < 4; attempt++) {
    const res = await fn();
    if (res.status !== 429) return res;
 
    // Honour what the server says; fall back to exponential backoff
    const retryAfter = Number(res.headers.get('retry-after'));
    const waitSec = Number.isFinite(retryAfter) && retryAfter > 0
      ? retryAfter
      : 2 ** attempt;
 
    await new Promise(r => setTimeout(r, waitSec * 1000));
  }
  throw new Error('rate limit: retries exhausted');
}
🚫

Do not retry a 429 in an unbounded loop. Put a ceiling on it and then surface the error. Unbounded retries turn a temporary slowdown into a lasting outage — on your side and on ours.

Staying under the limits

  • Use the batch endpoints. When feeding events, events/batch is far more efficient than single calls.
  • Cache your token. Minting one per call creates needless requests. → Authentication
  • Raise limit when paginating. A page of 100 means four times fewer requests than a page of 25. → Pagination
  • Take webhooks rather than polling. Receive a webhook instead of asking in a loop whether something changed. → Webhooks
⚠️

If the volume you expect is above the limits above, tell us in advance rather than discovering it by hitting them. Contact: [email protected]

Related