# Rate Limits

Understand how the Zaits API billing and rate limiting works.

## Overview

The Zaits API uses a **credit-based billing model**. Every subscription plan includes a monthly credit allowance, and each API call deducts credits based on the operation's complexity. When your monthly credits run out, you can purchase additional credits to keep going.

***

## Response Headers

All API responses include credit information:

```http
X-RateLimit-Limit: 4000
X-RateLimit-Remaining: 3847
X-RateLimit-Reset: 1740960000
X-RateLimit-Tier: basic
X-RateLimit-Billing-Method: credits
X-Credit-Balance: 3847
X-Credit-Cost: 2
```

| Header                       | Description                                                   |
| ---------------------------- | ------------------------------------------------------------- |
| `X-RateLimit-Limit`          | Monthly credit allowance for your plan                        |
| `X-RateLimit-Remaining`      | Current credit balance                                        |
| `X-RateLimit-Reset`          | Unix timestamp when monthly credits reset (1st of next month) |
| `X-RateLimit-Tier`           | Your subscription plan                                        |
| `X-RateLimit-Billing-Method` | `credits` or `admin_unlimited`                                |
| `X-Credit-Balance`           | Current credit balance                                        |
| `X-Credit-Cost`              | Credits this request cost                                     |

***

## Subscription Plans

Credits included per month and per-minute request limits:

| Plan           | Credits / Month | Per Minute | Concurrent |
| -------------- | --------------- | ---------- | ---------- |
| **Free**       | 20              | 10         | 1          |
| **Basic**      | 4,000           | 60         | 3          |
| **Pro**        | 20,000          | 300        | 10         |
| **Enterprise** | Unlimited       | 1,000      | 50         |

Monthly credits reset on the 1st of each month. Purchased credits never expire.

***

## Credit Costs per Endpoint

Each endpoint deducts a fixed number of credits per successful call:

| Endpoint                                | Credits | USD equivalent |
| --------------------------------------- | ------- | -------------- |
| `POST /ocr/extract/id`                  | 3       | $0.03          |
| `POST /ocr/extract/document`            | 2       | $0.02          |
| `POST /ocr/verify/authenticity`         | 3       | $0.03          |
| `POST /face/verify`                     | 2       | $0.02          |
| `POST /face/analyze`                    | 1       | $0.01          |
| `POST /face/detect`                     | 1       | $0.01          |
| `POST /face/landmarks`                  | 1       | $0.01          |
| `POST /face/liveness`                   | 3       | $0.03          |
| `POST /face-matching/enroll`            | 2       | $0.02          |
| `POST /face-matching/search`            | 2       | $0.02          |
| `POST /face-matching/verify/:id`        | 2       | $0.02          |
| `POST /fingerprint-matching/enroll`     | 2       | $0.02          |
| `POST /fingerprint-matching/search`     | 2       | $0.02          |
| `POST /fingerprint-matching/verify/:id` | 2       | $0.02          |
| `GET /email/verify`                     | 1       | $0.01          |
| `POST /email/verify/batch`              | 1       | $0.01          |
| `POST /signing/documents`               | 5       | $0.05          |
| `POST /mex/renapo/get-curp`             | 5       | $0.05          |
| `POST /mex/ine/validate-voter-list`     | 15      | $0.15          |

Credits are only deducted for **successful responses** (HTTP 2xx). Failed requests are not charged.

***

## Insufficient Credits Response

When you don't have enough credits, you'll receive a `429` response:

```json
{
  "success": false,
  "error": "insufficient_credits",
  "message": "Insufficient credits. This request costs 2 credit(s). Your current balance is 0 credits.",
  "error_code": "INSUFFICIENT_CREDITS",
  "details": {
    "credit_cost": 2,
    "credit_balance": 0,
    "needs_credits": true,
    "upgrade_message": "Upgrade to Professional for 20,000 credits per month",
    "reset_date": "2026-03-01T00:00:00.000Z"
  },
  "retry_after": 518400
}
```

**Headers included:**

```http
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 4000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1740960000
X-Credit-Cost: 2
```

***

## Handling Rate Limits

### Basic Retry Logic

```javascript
async function callWithRetry(apiCall, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await apiCall();
    } catch (error) {
      if (error.status === 429 && i < maxRetries - 1) {
        const retryAfter = error.retryAfter || Math.pow(2, i);
        await sleep(retryAfter * 1000);
        continue;
      }
      throw error;
    }
  }
}
```

### Python Example

```python
import time
import requests

def call_with_retry(api_call, max_retries=3):
    for attempt in range(max_retries):
        try:
            return api_call()
        except requests.HTTPError as e:
            if e.response.status_code == 429 and attempt < max_retries - 1:
                retry_after = int(e.response.headers.get('Retry-After', 2 ** attempt))
                time.sleep(retry_after)
                continue
            raise
```

***

## Best Practices

### 1. Monitor Credit Balance

Always check the credit headers in responses:

```javascript
const response = await fetch(apiUrl, options);
const balance = parseInt(response.headers.get('X-Credit-Balance'));
const cost = parseInt(response.headers.get('X-Credit-Cost'));
const reset = response.headers.get('X-RateLimit-Reset');

if (balance < 50) {
  console.warn(`Low credit balance: ${balance} credits remaining. Resets at ${new Date(reset * 1000)}`);
}
```

### 2. Implement Exponential Backoff

Wait progressively longer between retries:

* 1st retry: 1 second
* 2nd retry: 2 seconds
* 3rd retry: 4 seconds
* etc.

### 3. Use Request Queues

For high-volume applications, implement a queue to manage request rate:

* Track requests per minute
* Queue excess requests
* Process queue at sustainable rate

### 4. Cache Results

Cache API responses when appropriate:

* OCR results for static documents
* Face verification results (short TTL)
* Analysis results for known images

**Don't cache:**

* Real-time verification requests
* Liveness detection
* Time-sensitive operations

### 5. Batch When Possible

If processing multiple items, spread them out:

```javascript
async function processItems(items) {
  for (const item of items) {
    await processItem(item);
    await sleep(100); // 100ms delay between requests
  }
}
```

### 6. Handle 429 Gracefully

Always handle rate limit errors:

```javascript
try {
  const result = await apiCall();
} catch (error) {
  if (error.status === 429) {
    // Queue for retry or notify user
    console.log('Rate limited. Please try again in a moment.');
  } else {
    throw error;
  }
}
```

***

## Endpoint-Specific Limits

Some endpoints have different computational costs:

**Heavy Processing (50% of standard limit):**

* Face Analysis (age, gender, emotion)
* Face Landmarks detection
* Liveness Detection

**Light Operations (2x standard limit):**

* Usage Analytics
* Webhook Management
* API Key Management

***

## Monitoring Usage

Track your API usage in the dashboard:

* Current rate limit status
* Historical usage patterns
* Peak usage times
* Requests remaining

**Check programmatically:**

```bash
curl https://api.zaits.net/v1/usage/summary \
  -H "Authorization: Bearer YOUR_API_KEY"
```

***

## Common Issues

### Issue: Hitting Rate Limits Frequently

**Solutions:**

* Implement caching
* Use request queuing
* Spread requests over time
* Upgrade to higher tier

### Issue: Burst Traffic

**Solutions:**

* Implement request queue
* Use exponential backoff
* Consider Enterprise tier for burst allowance

### Issue: Multiple Services Sharing Key

**Solutions:**

* Use distributed rate limiting (Redis)
* Create separate API keys per service
* Implement centralized API gateway

***

## Rate Limit Tips

1. **Start conservative** - Don't use all your limit at once
2. **Monitor headers** - Track remaining requests
3. **Implement retries** - Always handle 429 errors
4. **Add delays** - Space out batch operations
5. **Cache results** - Reduce duplicate requests
6. **Upgrade when needed** - Don't let limits block your growth

***

## Getting Help

If you need custom rate limits:

* Contact support through your dashboard
* Enterprise plans include custom limits
* Rate limits can be adjusted based on use case

***

For more information:

* [Error Handling](/api/guides/error-handling.md)
* [Best Practices](/api/guides/best-practices.md)
* [Usage & Analytics API](/api/api-reference/usage-analytics.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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://zaits.gitbook.io/api/guides/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.
