Rate Limiting
Understand the API rate limits and how to handle them in your integration.
Last updated
The Filemonk API uses a token-bucket rate limiter to ensure fair usage across all stores.
How it works
Section titled “How it works”Each store’s API key has a bucket of points that refills every window:
| Parameter | Value |
|---|---|
| Bucket size | 40 points |
| Window | 60 seconds |
| GET request cost | 1 point |
| POST/PATCH/DELETE request cost | 2 points |
Every request you make deducts points from your bucket. When the bucket is empty, subsequent requests receive a 429 Too Many Requests response until the window resets.
Response headers
Section titled “Response headers”Every successful response includes rate limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum points allowed per window (e.g. 40) |
X-RateLimit-Remaining |
Points remaining in the current window |
X-RateLimit-Reset |
Unix timestamp when the current window resets |
X-RateLimit-Limit: 40X-RateLimit-Remaining: 37X-RateLimit-Reset: 1741608120Handling rate limit errors
Section titled “Handling rate limit errors”When you exceed the limit, the API returns a 429 response with a Retry-After header:
{ "error": "Rate limit exceeded", "retry_after": 23, "message": "You have exceeded the rate limit of 40 points per 60 seconds. Read requests cost 1 point(s) and write requests cost 2 point(s). Please retry after 23 second(s)."}-
Retry-After(integer, header)Number of seconds to wait before making another request.
Best practices
Section titled “Best practices”Implement exponential backoff
When you receive a 429 response, wait for the duration specified in Retry-After before retrying. If you continue to receive 429 responses, increase the wait time exponentially.
async function fetchWithRetry(url, options, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { const response = await fetch(url, options);
if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After'), 10) || 5; const waitTime = retryAfter * Math.pow(2, attempt) * 1000; await new Promise(resolve => setTimeout(resolve, waitTime)); continue; }
return response; } throw new Error('Max retries exceeded');}Monitor remaining points
Check the X-RateLimit-Remaining header after each response. If you are running low, slow down your request rate proactively instead of waiting for a 429.
Batch your reads
Use the list endpoint with a higher per_page value (up to 250) instead of making many individual requests. One request for 100 orders costs 1 point, while 100 individual order requests cost 100 points.
Thanks for letting us know.
Still stuck? Ask Quinn or chat with support