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

# Rate Limiting

> Understand the API rate limits and how to handle them in your integration.

The Filemonk API uses a token-bucket rate limiter to ensure fair usage across all stores.

## 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

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 |

```bash theme={null}
X-RateLimit-Limit: 40
X-RateLimit-Remaining: 37
X-RateLimit-Reset: 1741608120
```

## Handling rate limit errors

When you exceed the limit, the API returns a `429` response with a `Retry-After` header:

```json theme={null}
{
  "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)."
}
```

<ParamField header="Retry-After" type="integer">
  Number of seconds to wait before making another request.
</ParamField>

## Best practices

<AccordionGroup>
  <Accordion title="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.

    ```javascript theme={null}
    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');
    }
    ```
  </Accordion>

  <Accordion title="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`.
  </Accordion>

  <Accordion title="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.
  </Accordion>
</AccordionGroup>
