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

# Rate Limits

> Understanding API rate limits and throttling

## Rate Limiting Overview

Fetchin implements two types of rate limiting to ensure fair usage and system stability:

1. **Per-second rate limit**: Configurable per plan (default: 5 requests per second)
2. **Monthly quota**: Based on your plan (1,000 for Trial, custom for Enterprise)

### Rate Limit Structure

<CardGroup cols={2}>
  <Card title="Per-Second Limit" icon="clock">
    **Plan-based**

    Trial: 5 requests/second
    Enterprise: Custom RPS
  </Card>

  <Card title="Monthly Quota" icon="calendar">
    **Plan-based**

    Trial: 1,000 credits/month
    Enterprise: Custom
  </Card>
</CardGroup>

## Per-Second Rate Limit

Your per-second rate limit depends on your plan. Trial plans have a default of **5 requests per second**, while Enterprise plans can have custom limits.

### How It Works

* Requests are counted using a sliding window algorithm
* After exceeding your RPS limit, subsequent requests return `429`
* The limit is per API key and applies across all endpoints
* Most endpoints cost 1 unit per request; [`/post/engagement`](/api-reference/endpoint/get-post-engagement) costs **2 units**, so your plan's per-second limit must be at least 2 to call it
* Your specific RPS limit is visible in your dashboard

### Example (with 5 RPS limit)

```
Second 1: 5 requests ✅ (all succeed)
Second 1: 6th request ❌ (429 error)
Second 2: 5 requests ✅ (window slides, all succeed)
```

<Warning>
  Your RPS limit applies across ALL your requests. If you make 5 profile requests in one second (with a 5 RPS limit), you cannot make any posts requests until the window slides.
</Warning>

## Monthly Quota Limiting

Total credits allowed per month based on your plan:

* **Trial Plan**: 1,000 credits/month
* **Enterprise Plan**: Custom limits

### How It Works

* Each successful API request consumes credits from your monthly quota
* Failed requests (errors) also count toward quota
* Quota resets on your renewal date (monthly anniversary of signup)
* Unused credits do NOT carry over to next month

## Handling Rate Limit Errors

### 429 vs 402

The two limits return **different HTTP statuses** so you can tell them apart
from the status line alone (the `code` field carries the same distinction):

**Per-second limit exceeded** — `429 Too Many Requests` (`code: "RATE_LIMITED"`).
Back off and retry, honoring the `Retry-After` header (seconds):

```json theme={null}
{
  "error": "Rate limit exceeded. Try again later.",
  "code": "RATE_LIMITED"
}
```

**Monthly quota exhausted** — `402 Payment Required` (`code: "QUOTA_EXHAUSTED"`).
Upgrade your plan or wait for renewal; retrying won't help until then, and there
is no `Retry-After`:

```json theme={null}
{
  "error": "Quota exceeded. Upgrade your plan or wait for renewal.",
  "code": "QUOTA_EXHAUSTED"
}
```

### Response Headers

Each API response includes rate limit headers:

```
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 3
X-RateLimit-Reset: 1704067201
```

* `X-RateLimit-Limit`: Requests allowed per second (5)
* `X-RateLimit-Remaining`: Requests remaining this second
* `X-RateLimit-Reset`: Unix timestamp when limit resets

<Note>
  Rate limit headers show per-second limits. Check your dashboard for both your RPS limit and monthly quota information.
</Note>

<Tip>
  Enterprise plans can request custom RPS limits. Contact sales if you need higher throughput for your application.
</Tip>

## Best Practices

### 1. Respect Your RPS Limit

Space out your requests to stay under your rate limit (default: 5 per second for Trial plans):

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function fetchMultipleProfiles(profileUrls, apiKey) {
    const delay = 200; // 200ms = 5 req/s max
    const results = [];
    
    for (const url of profileUrls) {
      const response = await fetch(
        `https://api.fetchin.io/api/v1/profile?profileUrlOrUrn=${url}`,
        { headers: { 'X-API-Key': apiKey } }
      );
      
      results.push(await response.json());
      
      await new Promise(resolve => setTimeout(resolve, delay));
    }
    
    return results;
  }
  ```

  ```python Python theme={null}
  import time
  import requests

  def fetch_multiple_profiles(profile_urls, api_key):
      delay = 0.2  # 200ms = 5 req/s max
      results = []
      
      for url in profile_urls:
          response = requests.get(
              'https://api.fetchin.io/api/v1/profile',
              headers={'X-API-Key': api_key},
              params={'profileUrlOrUrn': url}
          )
          
          results.append(response.json())
          time.sleep(delay)
      
      return results
  ```
</CodeGroup>

### 2. Implement Retry Logic with Backoff

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function fetchWithRetry(url, options, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const waitTime = Math.pow(2, i) * 1000;
        await new Promise(resolve => setTimeout(resolve, waitTime));
        continue;
      }
      
      return response;
    }
    
    throw new Error('Max retries exceeded');
  }
  ```

  ```python Python theme={null}
  import time
  import requests

  def fetch_with_retry(url, headers, max_retries=3):
      for i in range(max_retries):
          response = requests.get(url, headers=headers)
          
          if response.status_code == 429:
              wait_time = (2 ** i) * 1
              time.sleep(wait_time)
              continue
              
          return response
      
      raise Exception('Max retries exceeded')
  ```
</CodeGroup>

### 3. Use Concurrency Control

Limit concurrent requests to respect the rate limit:

```javascript theme={null}
class RateLimiter {
  constructor(maxPerSecond = 5) {
    this.maxPerSecond = maxPerSecond;
    this.queue = [];
    this.processing = 0;
    this.lastReset = Date.now();
    this.requestsThisSecond = 0;
  }
  
  async add(fn) {
    while (this.requestsThisSecond >= this.maxPerSecond) {
      const now = Date.now();
      const timeSinceReset = now - this.lastReset;
      
      if (timeSinceReset >= 1000) {
        this.requestsThisSecond = 0;
        this.lastReset = now;
      } else {
        await new Promise(resolve => 
          setTimeout(resolve, 1000 - timeSinceReset)
        );
      }
    }
    
    this.requestsThisSecond++;
    return await fn();
  }
}

const limiter = new RateLimiter(5);

await limiter.add(() => fetchProfile(url1));
await limiter.add(() => fetchProfile(url2));
```

### 4. Check Quota Before Bulk Operations

Before processing large batches:

1. Check remaining quota in dashboard
2. Calculate how many requests you need
3. Process in chunks if quota is low

### 3. Queue Requests

For high-volume applications, implement a request queue:

```javascript theme={null}
class RequestQueue {
  constructor(maxConcurrent = 5) {
    this.maxConcurrent = maxConcurrent;
    this.running = 0;
    this.queue = [];
  }
  
  async add(fn) {
    if (this.running >= this.maxConcurrent) {
      await new Promise(resolve => this.queue.push(resolve));
    }
    
    this.running++;
    
    try {
      return await fn();
    } finally {
      this.running--;
      const resolve = this.queue.shift();
      if (resolve) resolve();
    }
  }
}
```

### 5. Cache Aggressively

Store results to avoid repeat requests:

```javascript theme={null}
const cache = new Map();

async function getCachedProfile(profileUrl, apiKey) {
  if (cache.has(profileUrl)) {
    return cache.get(profileUrl);
  }
  
  const response = await fetch(
    `https://api.fetchin.io/api/v1/profile?profileUrlOrUrn=${profileUrl}`,
    { headers: { 'X-API-Key': apiKey } }
  );
  
  const data = await response.json();
  cache.set(profileUrl, data);
  
  return data;
}
```

## Common Scenarios

### Batch Processing

Processing 100 profiles at 5 req/s:

```
100 profiles ÷ 5 req/s = 20 seconds minimum
```

Add buffer time for network latency and processing:

```
Estimated time: 22-25 seconds
```

### Real-Time Applications

For real-time applications making frequent requests:

1. Implement request queuing
2. Use websockets for updates when possible
3. Cache frequently accessed data
4. Batch multiple data points into single requests

<Tip>
  If you need higher rate limits for your use case, contact sales for an Enterprise plan with custom limits.
</Tip>

## Error Responses

### 429 Too Many Requests (Per-Second)

```json theme={null}
{
  "error": "Rate limit exceeded. Try again later.",
  "code": "RATE_LIMITED"
}
```

**Cause**: Exceeded your per-second rate limit

**Solution**:

* Wait 1 second before retrying
* Implement request spacing based on your RPS limit
* Use rate limiting library

### 402 Payment Required (Monthly Quota)

```json theme={null}
{
  "error": "Quota exceeded. Upgrade your plan or wait for renewal.",
  "code": "QUOTA_EXHAUSTED"
}
```

**Cause**: Monthly quota depleted

**Solution**:

* Wait for quota renewal
* Upgrade to higher quota plan
* Purchase additional credits (coming soon)

## Monitoring

Track your rate limit compliance:

* **Dashboard** - View daily usage patterns and monthly quota
* **Error rate** - Monitor `429` (rate limit) and `402` (quota exhausted) errors
* **Response headers** - Check `X-RateLimit-*` headers in responses
* **Success rate** - Ensure efficient request usage

<Warning>
  Both per-second rate limit violations AND monthly quota exceedances count as failed requests and still consume your monthly quota.
</Warning>
