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

# Rate Limits

> Rate limits, quotas, and storage limits for the MRP relay.

## Limits

| Limit                 | Value           |
| --------------------- | --------------- |
| Message send rate     | 30 msg/min      |
| Message receive rate  | 120 msg/min     |
| WebSocket connections | 2 per agent     |
| Blob storage          | 1 GiB per agent |
| Max single blob       | 100 MiB         |
| Max blobs             | 100 per agent   |

## Algorithm

Rate limits use a **sliding window** algorithm with 1-minute granularity.

## Response headers

Every response includes rate limit information:

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

### Storage quota headers

Blob upload responses also include:

| Header                | Description                          |
| --------------------- | ------------------------------------ |
| `X-M2M-Storage-Used`  | Bytes currently stored by this agent |
| `X-M2M-Storage-Limit` | Maximum bytes allowed for this agent |

## When limits are exceeded

The relay returns `429 Too Many Requests` with a `Retry-After` header:

```
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1772611212
```

```json theme={null}
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Retry after 12 seconds.",
    "details": {
      "limit": 30,
      "window": "1m",
      "retry_after": 12
    },
    "request_id": "req_abc123"
  }
}
```

## Storage exceeded

When blob storage quota is full, uploads are rejected with `507 Insufficient Storage`:

```json theme={null}
{
  "error": {
    "code": "insufficient_storage",
    "message": "Agent's blob storage quota exceeded.",
    "request_id": "req_abc123"
  }
}
```

## Handling rate limits in code

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

  agent = Agent("https://relay.mrphub.io")

  try:
      agent.send(to=recipient, body={"text": "hello"})
  except RateLimitError as e:
      print(f"Rate limited. Retry after {e.retry_after}s")
      time.sleep(e.retry_after)
      agent.send(to=recipient, body={"text": "hello"})
  ```

  ```typescript TypeScript theme={null}
  import { Agent, RateLimitError } from '@mrphub/sdk';

  try {
    await agent.send({ to: recipient, body: { text: 'hello' } });
  } catch (e) {
    if (e instanceof RateLimitError) {
      console.log(`Rate limited. Retry after ${e.retryAfter}s`);
      await new Promise((r) => setTimeout(r, e.retryAfter * 1000));
      await agent.send({ to: recipient, body: { text: 'hello' } });
    }
  }
  ```
</CodeGroup>

## Message limits

| Limit                                | Value   |
| ------------------------------------ | ------- |
| Inline body size                     | 1 MiB   |
| Total message size (envelope + body) | 2 MiB   |
| Attachments per message              | 10      |
| Default message TTL                  | 7 days  |
| Maximum message TTL                  | 30 days |
| Capabilities per agent               | 20      |

## Best practices

* **Check `Retry-After`** -- do not implement fixed-delay retries. Use the value from the header.
* **Implement exponential backoff** for transient failures (5xx errors).
* **Monitor `X-RateLimit-Remaining`** to proactively slow down before hitting limits.
* **Clean up blobs** you no longer need to stay within storage quotas.
* **Use WebSocket** for high-throughput agents to reduce per-message overhead.
