# Rate Limits

### Overview

Rate limits protect the API from abuse and ensure fair usage for all users. Different endpoint types have different limits.

### Rate Limit Tiers

| Tier      | Limit              | Applies To           |
| --------- | ------------------ | -------------------- |
| Standard  | 60 requests/minute | Most `GET` endpoints |
| Expensive | 10 requests/minute | Proxy generation     |

#### Expensive Operations

These endpoints have stricter limits:

* `POST /proxies/generate` — Proxy generation

### Rate Limit Headers

Every response includes rate limit information:

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1704067200
```

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

### Rate Limit Exceeded

When you exceed the rate limit, you'll receive a `429` response:

```json
{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests.",
    "details": {
      "retry_after": 45
    }
  }
}
```

Additional headers:

```
Retry-After: 45
```

### Handling Rate Limits

#### Python — Exponential Backoff

```python
import time
import requests

def make_request_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 60))
            print(f"Rate limited. Waiting {retry_after} seconds...")
            time.sleep(retry_after)
            continue

        return response

    raise Exception("Max retries exceeded")
```

#### JavaScript — Fetch with Retry

```javascript
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") || "60");
      console.log(`Rate limited. Waiting ${retryAfter}s...`);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      continue;
    }

    return response;
  }

  throw new Error("Max retries exceeded");
}
```

### Best Practices

#### 1. Monitor Rate Limit Headers

Check `X-RateLimit-Remaining` before making requests:

```python
remaining = int(response.headers.get("X-RateLimit-Remaining", 0))
if remaining < 5:
    print("Warning: Approaching rate limit")
```

#### 2. Cache Responses

Cache data that doesn't change frequently:

* Country lists
* Plan information
* User profile data

#### 3. Spread Requests

Don't burst all requests at once. Spread them over time:

```python
import time

for item in items:
    process(item)
    time.sleep(1)  # 1 second between requests
```

### Troubleshooting

#### Consistently hitting limits?

* **Audit your requests** — Are you making unnecessary calls?
* **Implement caching** — Store responses locally
* **Check for loops** — Ensure you're not making duplicate requests
* **Contact support** — We can help optimize your integration

#### Getting 429 errors unexpectedly?

* Rate limits are per API key, not per IP
* Multiple applications using the same key share limits
* Use separate keys for different applications


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.plainproxies.com/getting-started/rate-limits.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
