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

# Rate Limiting

> Per-wallet rate limits and how to handle 429 responses.

## Limits

MemoClaw applies rate limits per wallet address to ensure fair usage.

| Scope                 | Limit        | Window   |
| --------------------- | ------------ | -------- |
| All endpoints         | 100 requests | 1 minute |
| Extract / Consolidate | 10 requests  | 1 minute |

<Info>
  Rate limits are per wallet address, not per API key or IP. If you use the same wallet from multiple agents, they share the same limit.
</Info>

## Response Headers

Every response includes rate limit headers:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1706889600
```

| Header                  | Description                              |
| ----------------------- | ---------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed in the window   |
| `X-RateLimit-Remaining` | Requests remaining in the current window |
| `X-RateLimit-Reset`     | Unix timestamp when the window resets    |

## Handling 429 Responses

When rate limited, you'll receive a `429` response:

```json theme={null}
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded",
    "details": {
      "limit": 100,
      "reset_at": "2025-01-15T12:00:00Z"
    }
  }
}
```

### Retry Strategy

Use exponential backoff with the `X-RateLimit-Reset` header:

<CodeGroup>
  ```python Python theme={null}
  import time
  from memoclaw import MemoClaw, RateLimitError

  client = MemoClaw()

  def recall_with_retry(query, max_retries=3):
      for attempt in range(max_retries):
          try:
              return client.recall(query)
          except RateLimitError as e:
              if attempt == max_retries - 1:
                  raise
              wait = 2 ** attempt
              time.sleep(wait)
  ```

  ```typescript TypeScript (fetch) theme={null}
  async function recallWithRetry(query: string, authHeader: string, maxRetries = 3) {
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      const res = await fetch("https://api.memoclaw.com/v1/recall", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-wallet-auth": authHeader,
        },
        body: JSON.stringify({ query }),
      });
      if (res.ok) return res.json();
      if (res.status !== 429 || attempt === maxRetries - 1) {
        throw new Error(`Request failed: ${res.status}`);
      }
      await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
    }
  }
  ```
</CodeGroup>

## Tips

* **Batch stores** instead of individual calls — `POST /v1/store/batch` handles up to 100 memories in one request
* **Use `ingest`** instead of multiple `extract` + `store` calls
* **Cache recall results** client-side when the same query is used repeatedly
