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

# Rate Limits

> Understanding API rate limits and how to handle them

The Buena.ai API uses rate limiting to ensure fair usage and maintain system stability. All limits are applied per API key.

## Current Limits

<CardGroup cols={3}>
  <Card title="Per Minute" icon="clock">
    **60 requests** Short burst protection
  </Card>

  <Card title="Per Hour" icon="hourglass-half">
    **1,000 requests** Sustained usage limit
  </Card>

  <Card title="Per Day" icon="calendar-day">
    **10,000 requests** Daily usage quota
  </Card>
</CardGroup>

## Rate Limit Headers

Every API response includes rate limit information in the headers:

```bash theme={null}
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1640995200
X-RateLimit-Window: minute
```

### Header Descriptions

| Header                  | Description                                   |
| ----------------------- | --------------------------------------------- |
| `X-RateLimit-Limit`     | Total requests allowed in the current window  |
| `X-RateLimit-Remaining` | Requests remaining in the current window      |
| `X-RateLimit-Reset`     | Unix timestamp when the current window resets |
| `X-RateLimit-Window`    | Current window type (`minute`, `hour`, `day`) |

## Rate Limit Exceeded Response

When you exceed a rate limit, the API returns a `429 Too Many Requests` response:

```json theme={null}
{
  "error": true,
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "Rate limit exceeded. Try again in 45 seconds.",
  "version": "2.0",
  "timestamp": "2024-01-20T15:30:00Z",
  "retryAfter": 45,
  "rateLimitInfo": {
    "limit": 60,
    "remaining": 0,
    "reset": 1640995245,
    "window": "minute"
  }
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Implement Exponential Backoff">
    When you receive a 429 response, wait before retrying:

    ```javascript theme={null}
    async function makeRequestWithBackoff(url, options, maxRetries = 3) {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
        const response = await fetch(url, options);
        
        if (response.status !== 429) {
          return response;
        }
        
        const retryAfter = response.headers.get('retry-after') || 
                          Math.pow(2, attempt); // Exponential backoff
        
        await new Promise(resolve => 
          setTimeout(resolve, retryAfter * 1000)
        );
      }
      
      throw new Error('Max retries exceeded');
    }
    ```
  </Accordion>

  <Accordion title="Monitor Rate Limit Headers">
    Check headers before making requests:

    ```javascript theme={null}
    function checkRateLimit(response) {
      const remaining = parseInt(
        response.headers.get('X-RateLimit-Remaining')
      );
      const reset = parseInt(
        response.headers.get('X-RateLimit-Reset')
      );
      
      if (remaining < 5) {
        const waitTime = reset - Math.floor(Date.now() / 1000);
        console.warn(`Rate limit low. ${remaining} requests remaining. 
                     Resets in ${waitTime} seconds.`);
      }
      
      return { remaining, reset };
    }
    ```
  </Accordion>

  <Accordion title="Distribute Requests Evenly">
    Avoid bursts by spacing out requests:

    ```javascript theme={null}
    class RateLimitedClient {
      constructor(apiKey) {
        this.apiKey = apiKey;
        this.requestQueue = [];
        this.processing = false;
        this.minInterval = 1000; // 1 second between requests
      }
      
      async request(url, options) {
        return new Promise((resolve, reject) => {
          this.requestQueue.push({ url, options, resolve, reject });
          this.processQueue();
        });
      }
      
      async processQueue() {
        if (this.processing || this.requestQueue.length === 0) return;
        
        this.processing = true;
        
        while (this.requestQueue.length > 0) {
          const { url, options, resolve, reject } = this.requestQueue.shift();
          
          try {
            const response = await fetch(url, {
              ...options,
              headers: {
                ...options.headers,
                'x-api-key': this.apiKey,
              },
            });
            resolve(response);
          } catch (error) {
            reject(error);
          }
          
          // Wait before next request
          await new Promise(resolve => 
            setTimeout(resolve, this.minInterval)
          );
        }
        
        this.processing = false;
      }
    }
    ```
  </Accordion>

  <Accordion title="Batch Operations When Possible">
    Use bulk endpoints to reduce request count:

    ```javascript theme={null}
    // Instead of multiple single lead creations
    // ❌ This uses multiple requests
    for (const lead of leads) {
      await createLead(lead);
    }

    // ✅ Use bulk prospect upload
    await uploadProspects(leads);
    ```
  </Accordion>
</AccordionGroup>

## Rate Limit Strategies

### 1. Proactive Monitoring

Monitor your usage with the stats endpoint:

```bash theme={null}
curl -H "x-api-key: YOUR_API_KEY" \
     "https://api.buena.ai/api/v2/keys/stats"
```

Response:

```json theme={null}
{
  "success": true,
  "data": {
    "totalKeys": 3,
    "activeKeys": 2,
    "totalUsage": 1250,
    "dailyUsage": {
      "2024-01-20": 45,
      "2024-01-19": 67,
      "2024-01-18": 23
    }
  }
}
```

### 2. Request Queuing

Implement a queue system for high-volume operations:

```python theme={null}
import asyncio
import time
from typing import List, Dict, Any

class BuenaAPIClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.rate_limit = {
            'minute': {'limit': 60, 'remaining': 60, 'reset': 0},
            'hour': {'limit': 1000, 'remaining': 1000, 'reset': 0},
            'day': {'limit': 10000, 'remaining': 10000, 'reset': 0}
        }

    async def make_request(self, endpoint: str, method: str = 'GET', data: Dict = None):
        # Wait if rate limit is low
        await self._wait_if_needed()

        # Make request
        response = await self._http_request(endpoint, method, data)

        # Update rate limit info from headers
        self._update_rate_limits(response.headers)

        return response

    async def _wait_if_needed(self):
        now = time.time()

        for window, limits in self.rate_limit.items():
            if limits['remaining'] <= 1 and limits['reset'] > now:
                wait_time = limits['reset'] - now
                print(f"Rate limit reached for {window}. Waiting {wait_time:.1f}s")
                await asyncio.sleep(wait_time + 1)
```

### 3. Intelligent Caching

Cache responses to reduce API calls:

```javascript theme={null}
class CachedBuenaClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.cache = new Map();
    this.cacheTTL = 5 * 60 * 1000; // 5 minutes
  }

  async getLeads(params = {}) {
    const cacheKey = `leads:${JSON.stringify(params)}`;
    const cached = this.cache.get(cacheKey);

    if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
      return cached.data;
    }

    const response = await this.makeRequest("/leads", { params });
    const data = await response.json();

    this.cache.set(cacheKey, {
      data,
      timestamp: Date.now(),
    });

    return data;
  }
}
```

## Error Handling Examples

### JavaScript/Node.js

```javascript theme={null}
async function handleRateLimit(apiCall) {
  let retries = 0;
  const maxRetries = 3;

  while (retries < maxRetries) {
    try {
      const response = await apiCall();

      if (response.status === 429) {
        const retryAfter =
          response.headers.get("retry-after") || Math.pow(2, retries);

        console.log(`Rate limited. Retrying in ${retryAfter}s...`);
        await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));

        retries++;
        continue;
      }

      return response;
    } catch (error) {
      console.error("Request failed:", error);
      retries++;

      if (retries >= maxRetries) throw error;

      await new Promise((resolve) =>
        setTimeout(resolve, Math.pow(2, retries) * 1000)
      );
    }
  }
}
```

### Python

```python theme={null}
import time
import requests
from typing import Optional

def make_request_with_retry(
    url: str,
    headers: dict,
    max_retries: int = 3,
    base_delay: float = 1.0
) -> Optional[requests.Response]:

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

            if response.status_code == 429:
                retry_after = int(response.headers.get('retry-after', base_delay * (2 ** attempt)))
                print(f"Rate limited. Waiting {retry_after}s before retry {attempt + 1}/{max_retries}")
                time.sleep(retry_after)
                continue

            return response

        except requests.RequestException as e:
            if attempt == max_retries - 1:
                raise e

            delay = base_delay * (2 ** attempt)
            print(f"Request failed. Retrying in {delay}s...")
            time.sleep(delay)

    return None
```

## Monitoring and Alerts

Set up monitoring to track your API usage:

### 1. Usage Tracking

```javascript theme={null}
class UsageTracker {
  constructor() {
    this.usage = {
      minute: 0,
      hour: 0,
      day: 0,
    };
    this.resetTimers();
  }

  trackRequest() {
    this.usage.minute++;
    this.usage.hour++;
    this.usage.day++;

    this.checkThresholds();
  }

  checkThresholds() {
    if (this.usage.minute > 50) {
      console.warn("Approaching minute rate limit");
    }
    if (this.usage.hour > 800) {
      console.warn("Approaching hourly rate limit");
    }
    if (this.usage.day > 8000) {
      console.warn("Approaching daily rate limit");
    }
  }

  resetTimers() {
    setInterval(() => (this.usage.minute = 0), 60 * 1000);
    setInterval(() => (this.usage.hour = 0), 60 * 60 * 1000);
    setInterval(() => (this.usage.day = 0), 24 * 60 * 60 * 1000);
  }
}
```

### 2. Alerting

```python theme={null}
import logging
from datetime import datetime, timedelta

class RateLimitMonitor:
    def __init__(self, alert_threshold=0.8):
        self.alert_threshold = alert_threshold
        self.logger = logging.getLogger(__name__)

    def check_limits(self, headers):
        limit = int(headers.get('X-RateLimit-Limit', 0))
        remaining = int(headers.get('X-RateLimit-Remaining', 0))
        window = headers.get('X-RateLimit-Window', 'unknown')

        usage_percent = (limit - remaining) / limit if limit > 0 else 0

        if usage_percent >= self.alert_threshold:
            self.logger.warning(
                f"High API usage: {usage_percent:.1%} of {window} limit used. "
                f"{remaining} requests remaining."
            )

            # Send alert to monitoring system
            self.send_alert(window, usage_percent, remaining)

    def send_alert(self, window, usage_percent, remaining):
        # Implement your alerting logic here
        # e.g., send to Slack, PagerDuty, etc.
        pass
```

## Need Higher Limits?

If your application requires higher rate limits, contact our support team at [support@buena.ai](mailto:support@buena.ai) with:

* Your use case description
* Expected request volume
* Current API key prefix
* Business justification

We offer custom rate limits for enterprise customers and high-volume integrations.
