The SpeyBooks API applies rate limits per IP address to protect the platform and ensure fair usage across all accounts. Limits vary by endpoint sensitivity.
Default limit
Most API endpoints allow 100 requests per minute per IP address. This applies to all authenticated resource endpoints (invoices, contacts, transactions, accounts, quotes, reports, and so on) unless a stricter limit is specified below.
Authentication endpoints
Auth endpoints use tighter limits to protect against credential stuffing, brute force, and email flooding. These override the default limit.
| Endpoint | Limit | Window | Purpose |
|---|---|---|---|
| Login | 5 requests | 15 minutes | Credential stuffing protection |
| TOTP verification | 5 requests | 15 minutes | TOTP brute force protection |
| Token refresh | 20 requests | 15 minutes | Normal app operation (more lenient) |
| Registration | 3 requests | 1 hour | Mass account creation prevention |
| Password reset | 3 requests | 1 hour | Email flooding prevention |
| Email verification resend | 3 requests | 1 hour | Email flooding prevention |
All auth rate limits are keyed by IP address. The account lockout mechanism (5 failed login attempts, 15-minute lockout) operates independently of rate limiting and is tracked per account rather than per IP.
Response headers
Every response includes rate limit headers so your client can track usage proactively.
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Exceeding the limit
When you exceed the rate limit, the API returns a 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait before retrying.
Handling rate limits
Your client should check the Retry-After header and wait the specified duration before retrying. If the header is not present, use exponential backoff starting at 1 second with a maximum delay of 30 seconds.
For batch operations, avoid sending requests in tight loops. Space requests evenly across the window or use perPage=100 on list endpoints to reduce the total number of calls needed.
Best practices
Respect X-RateLimit-Remaining and slow down before hitting zero rather than waiting for a 429. Cache responses where appropriate, particularly for data that changes infrequently like chart of accounts or organisation details. If your integration needs to process large volumes, use pagination efficiently and consider queuing requests with controlled concurrency.