Rate Limits
The API enforces rate limits per tenant to ensure fair usage and platform stability. Limits vary by tenant tier and endpoint group.
Limits by Tier
| Tier | General (15 min) | Auth (15 min) | Transfers (15 min) |
|---|---|---|---|
starter | 100 | 50 | 50 |
pro | 500 | 100 | 200 |
enterprise | 2,000 | 500 | 1,000 |
note
Sandbox environments use 10x the production limits to facilitate testing. See Sandbox Testing.
Response Headers
Every response includes rate limit headers:
| Header | Description | Example |
|---|---|---|
RateLimit-Limit | Maximum requests per window | 100 |
RateLimit-Remaining | Requests remaining in current window | 87 |
RateLimit-Reset | Unix timestamp when the window resets | 1740009600 |
HTTP/1.1 200 OK
RateLimit-Limit: 100
RateLimit-Remaining: 87
RateLimit-Reset: 1740009600
Rate Limit Exceeded
When you exceed the limit, the API returns:
HTTP/1.1 429 Too Many Requests
Retry-After: 120
{
"success": false,
"error": "Too many requests",
"code": "RATE_LIMIT_EXCEEDED"
}
The Retry-After header tells you how many seconds to wait before retrying.
Authentication Rate Limits
Login endpoints have stricter limits to prevent brute-force attacks:
| Endpoint | Limit (15 min) | Notes |
|---|---|---|
POST /api/v1/auth/login | 50 | Successful requests don't count |
POST /api/v1/auth/refresh | 100 | — |
POST /api/v1/registration/forgot-password | 10 | Per email address |
POST /api/v1/registration/reset-password | 10 | Per token |
Successful login requests are not counted against the rate limit — only failed attempts count.
Handling Rate Limits
Check Headers Before Retrying
async function apiCall(url, options) {
const res = await fetch(url, options);
const remaining = parseInt(res.headers.get("RateLimit-Remaining"));
const resetAt = parseInt(res.headers.get("RateLimit-Reset"));
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("Retry-After")) || 60;
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return apiCall(url, options); // Retry once
}
// Log when approaching limit
if (remaining < 10) {
console.warn(`Rate limit low: ${remaining} remaining, resets at ${new Date(resetAt * 1000)}`);
}
return res;
}
Strategies
- Monitor
RateLimit-Remaining— Back off when approaching zero. - Use exponential backoff — On 429 responses, wait the
Retry-Afterduration before retrying. - Batch operations — Use bulk endpoints (e.g.
POST /api/v1/bulk-transfers) instead of multiple individual calls. - Cache responses — Cache list responses (accounts, beneficiaries, billers) to reduce API calls.
- Upgrade your tier — If you consistently hit limits, contact support to upgrade.
Request Counting
- Each API call counts as one request regardless of response status (except where noted).
- Websocket connections are not rate-limited.
- Public endpoints (
/api/v1/theme,/api/v1/fx-rates,/health) have separate, higher limits.
Next Steps
- Error Codes — Full error reference including
RATE_LIMIT_EXCEEDED. - API Reference — Base URL and response format.
- Sandbox Testing — Higher limits in sandbox mode.