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

> ## Agent Instructions
> Company name is Akhara AI (never Rubric AI). Keep lowercase rubric/rubrics only when meaning grading criteria.
> Expert Review (docs path talent/) is enterprise BYO experts for audit and review: invite customer specialists; do not pitch Akhara recruiting or a public expert career portal. RLHF and domain writing are secondary work types.
> Prefer concrete API examples against public hosts: Environments eval API https://agi.akhara.ai, Control plane PDP https://api.akhara.dev, Evaluation https://app.akhara.ai / https://api.akhara.ai, Expert Review portal https://talent.akhara.ai.
> Do not invent a public hostname for private orchestrators or env API internals.
> Do not confuse control-plane latches with Environments confirmation latches.
> Environments SDK/API examples: curl against https://agi.akhara.ai. Evaluation SDK: from akhara import Akhara and AKHARA_API_KEY.
> Start with /llms.txt for the docs index and OpenAPI links; fetch individual pages as .md exports.

# Rate Limits & Quotas

> Understanding API rate limits, usage quotas, and how to handle limit errors.

## Overview

Akhara enforces rate limits to ensure fair usage and system stability. Rate limits are applied per API key and vary by endpoint and plan tier.

***

## Rate Limits

### Default Limits by Plan

| Plan       | Requests/min | Requests/hour | Concurrent |
| ---------- | ------------ | ------------- | ---------- |
| Starter    | 60           | 1,000         | 5          |
| Pro        | 300          | 10,000        | 20         |
| Enterprise | 1,000        | 50,000        | 100        |

### Limits by Endpoint Category

| Category                          | Starter | Pro     | Enterprise |
| --------------------------------- | ------- | ------- | ---------- |
| **Read operations** (GET)         | 100/min | 500/min | 2,000/min  |
| **Write operations** (POST/PATCH) | 60/min  | 300/min | 1,000/min  |
| **Batch operations**              | 10/min  | 50/min  | 200/min    |
| **Export operations**             | 5/min   | 20/min  | 100/min    |
| **Evaluation runs**               | 10/min  | 50/min  | 200/min    |

### Endpoint-Specific Limits

Some endpoints have specific limits due to resource intensity:

| Endpoint                                 | Limit        | Reason            |
| ---------------------------------------- | ------------ | ----------------- |
| `POST /v1/evaluations`                   | 10/min       | Compute-intensive |
| `POST /v1/datasets/{id}/samples` (batch) | 20/min       | Storage-intensive |
| `POST /v1/audit/reports`                 | 5/min        | Report generation |
| `GET /v1/audit/stream`                   | 1 concurrent | SSE connection    |

***

## Rate Limit Headers

Every API response includes rate limit information in headers:

| Header                  | Description                              |
| ----------------------- | ---------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed in window       |
| `X-RateLimit-Remaining` | Requests remaining in current window     |
| `X-RateLimit-Reset`     | Unix timestamp when window resets        |
| `X-RateLimit-Window`    | Window duration in seconds               |
| `Retry-After`           | Seconds to wait before retrying (on 429) |

### Example Response Headers

```
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 245
X-RateLimit-Reset: 1705327200
X-RateLimit-Window: 60
```

### Example 429 Response

```
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705327200
Retry-After: 32
Content-Type: application/json

{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Retry after 32 seconds.",
    "details": {
      "limit": 300,
      "window": "60s",
      "retry_after": 32
    }
  }
}
```

***

## Usage Quotas

Quotas limit total usage over billing periods, separate from rate limits.

### Quota Types by Plan

| Quota                       | Starter | Pro     | Enterprise |
| --------------------------- | ------- | ------- | ---------- |
| **Samples stored**          | 10,000  | 100,000 | Unlimited  |
| **Evaluations/month**       | 100     | 1,000   | Unlimited  |
| **Samples evaluated/month** | 50,000  | 500,000 | Unlimited  |
| **Human reviews/month**     | 500     | 5,000   | Unlimited  |
| **Reviewer seats**          | 3       | 20      | Unlimited  |
| **Projects**                | 5       | 25      | Unlimited  |
| **Data retention**          | 90 days | 1 year  | 7 years    |
| **Audit log retention**     | 90 days | 1 year  | 7 years    |

### Checking Quota Usage

<CodeGroup>
  ```python Python theme={null}
  from akhara import Akhara

  client = Akhara()

  # Get current usage
  usage = client.usage.get()

  print(f"Samples: {usage.samples.current}/{usage.samples.limit}")
  print(f"Evaluations: {usage.evaluations.current}/{usage.evaluations.limit}")
  print(f"Reviews: {usage.reviews.current}/{usage.reviews.limit}")
  print(f"Billing period: {usage.period_start} to {usage.period_end}")
  ```

  ```bash cURL theme={null}
  curl "https://api.akhara.ai/v1/usage" \
    -H "Authorization: Bearer rb_live_xxxxxxxx"
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "object": "usage",
  "plan": "pro",
  "period_start": "2024-01-01T00:00:00Z",
  "period_end": "2024-01-31T23:59:59Z",
  "samples": {
    "current": 45000,
    "limit": 100000,
    "percent_used": 45
  },
  "evaluations": {
    "current": 234,
    "limit": 1000,
    "percent_used": 23.4
  },
  "samples_evaluated": {
    "current": 156000,
    "limit": 500000,
    "percent_used": 31.2
  },
  "reviews": {
    "current": 1245,
    "limit": 5000,
    "percent_used": 24.9
  },
  "reviewers": {
    "current": 8,
    "limit": 20
  },
  "projects": {
    "current": 12,
    "limit": 25
  }
}
```

***

## Handling Rate Limits

### Basic Retry with Backoff

```python theme={null}
import time
from akhara import Akhara, RateLimitError

client = Akhara()

def call_with_retry(func, max_retries=5):
    for attempt in range(max_retries):
        try:
            return func()
        except RateLimitError as e:
            if attempt == max_retries - 1:
                raise
            
            wait_time = e.retry_after or (2 ** attempt)
            print(f"Rate limited. Waiting {wait_time}s...")
            time.sleep(wait_time)

# Usage
result = call_with_retry(
    lambda: client.datasets.list(project="proj_abc123")
)
```

### Proactive Rate Limiting

Check remaining quota before making requests:

```python theme={null}
import time

class RateLimitedClient:
    def __init__(self, client):
        self.client = client
        self.remaining = None
        self.reset_at = None
    
    def request(self, func):
        # Wait if we're out of quota
        if self.remaining is not None and self.remaining <= 0:
            wait_time = self.reset_at - time.time()
            if wait_time > 0:
                time.sleep(wait_time)
        
        response = func()
        
        # Update from headers
        self.remaining = response.headers.get('X-RateLimit-Remaining')
        self.reset_at = response.headers.get('X-RateLimit-Reset')
        
        return response
```

### Batch Operations

Reduce API calls by using batch endpoints:

```python theme={null}
# ❌ Bad: Many individual calls
for sample in samples:
    client.datasets.add_sample(dataset="ds_xyz", **sample)

# ✅ Good: Single batch call
client.datasets.add_samples(
    dataset="ds_xyz",
    samples=samples  # Up to 100 per batch
)
```

### Parallel Requests with Limits

Control concurrency to stay within limits:

```python theme={null}
import asyncio
from akhara import AsyncAkhara

client = AsyncAkhara()
semaphore = asyncio.Semaphore(10)  # Max 10 concurrent

async def fetch_with_limit(sample_id):
    async with semaphore:
        return await client.datasets.get_sample(
            dataset="ds_xyz",
            sample=sample_id
        )

async def fetch_all(sample_ids):
    tasks = [fetch_with_limit(sid) for sid in sample_ids]
    return await asyncio.gather(*tasks)

# Run
samples = asyncio.run(fetch_all(sample_ids))
```

***

## Quota Alerts

Configure alerts when approaching quota limits:

```python theme={null}
# Set up quota alerts
client.alerts.create(
    type="quota_warning",
    config={
        "metrics": ["samples", "evaluations", "reviews"],
        "threshold_percent": 80,  # Alert at 80% usage
        "channels": ["email", "slack"],
        "recipients": ["admin@company.com"]
    }
)
```

### Webhook Payload

```json theme={null}
{
  "event": "quota.threshold_reached",
  "timestamp": "2024-01-20T15:00:00Z",
  "data": {
    "metric": "evaluations",
    "current": 820,
    "limit": 1000,
    "percent_used": 82,
    "threshold": 80,
    "period_end": "2024-01-31T23:59:59Z"
  }
}
```

***

## Requesting Limit Increases

### Temporary Increases

For one-time events (e.g., large data migration):

```python theme={null}
# Request temporary limit increase
request = client.support.request_limit_increase(
    reason="One-time migration of 500k samples",
    requested_limits={
        "samples_per_batch": 500,
        "requests_per_minute": 1000
    },
    duration_hours=24,
    start_time="2024-02-01T00:00:00Z"
)

print(f"Request ID: {request.id}")
print(f"Status: {request.status}")  # pending, approved, denied
```

### Permanent Increases

Contact sales for permanent limit increases:

* **Pro → Enterprise upgrade**: Unlimited quotas
* **Custom enterprise limits**: Tailored to your needs
* **Dedicated infrastructure**: Isolated rate limits

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Use Batch APIs" icon="layer-group">
    Combine multiple operations into batch requests when possible
  </Card>

  <Card title="Implement Backoff" icon="clock-rotate-left">
    Always implement exponential backoff for 429 responses
  </Card>

  <Card title="Cache Responses" icon="database">
    Cache read results to reduce API calls
  </Card>

  <Card title="Monitor Usage" icon="chart-line">
    Set up alerts before hitting limits
  </Card>
</CardGroup>

### Do's and Don'ts

| ✅ Do                                      | ❌ Don't                               |
| ----------------------------------------- | ------------------------------------- |
| Use batch endpoints for bulk operations   | Make individual calls in tight loops  |
| Respect `Retry-After` header              | Retry immediately after 429           |
| Cache frequently accessed data            | Fetch the same data repeatedly        |
| Use webhooks for real-time updates        | Poll for status changes               |
| Pre-fetch data during low-traffic periods | Run bulk operations during peak hours |

***

## Related

<CardGroup cols={2}>
  <Card title="Errors & Status Codes" icon="triangle-exclamation" href="/evaluation/api-reference/errors">
    Handling API errors
  </Card>

  <Card title="Billing" icon="credit-card" href="https://app.akhara.ai/settings/billing">
    Upgrade your plan
  </Card>
</CardGroup>
