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

# Rate Limits

> Understanding API key rate limiting and optimization strategies

## Overview

The Junis External API implements rate limiting to ensure fair usage and maintain service quality for all users. Rate limits are applied **per API key**, and all keys of an organization also share one **organization-wide** per-minute total. Per-key limits can be adjusted by an organization admin.

**Base URL**: `https://api.junis.ai`

<Note>
  Each API key has its own per-minute and per-hour counters. On top of that, all keys of an organization share one per-minute total (300 requests by default), so creating more keys does not raise the organization's total.
</Note>

***

## Rate Limiting Architecture

The External API uses **Redis-based fixed-window counters** with three windows (per key per minute, per key per hour, per organization per minute) for distributed rate limiting across multiple server instances.

<AccordionGroup>
  <Accordion title="How It Works" icon="gears">
    **Storage**: Redis with distributed support across all API servers

    **Windows**: Three fixed windows aligned to the clock

    * **Per key, per minute**: resets at the start of every minute
    * **Per key, per hour**: resets at the start of every hour
    * **Per organization, per minute**: all keys of the organization combined, resets at the start of every minute

    **Algorithm**: Fixed-window counters with atomic increments (one Redis round trip per request)
  </Accordion>

  <Accordion title="Rate Limit Enforcement" icon="shield">
    **Check Before Request**: Rate limits are checked before processing your request

    **Headers Included**: Every response includes current rate limit status

    **429 on Exceed**: Returns `429 Too Many Requests` if limit exceeded

    **Automatic Reset**: Counters automatically reset at the end of each window
  </Accordion>
</AccordionGroup>

***

## Default Rate Limits

When you create a new API key, the following default limits apply:

| Limit | Organization key (Admin → API Keys) | Personal key (Settings → API Keys) |
| - | - | - |
| **Requests per minute, per key** | 100 | 100 |
| **Requests per hour, per key** | 3,000 | 2,000 |
| **Requests per minute, whole organization** | 300 (all keys combined) | 300 (all keys combined) |

<Tip>
  Per-key limits of an existing key can be raised or lowered by an organization admin through the admin API (`PUT /api/admin/api-keys/{key_id}` with `rate_limit_per_minute` 1–1,000 and/or `rate_limit_per_hour` 1–100,000). The change applies from the next request, with no redeploy. The organization-wide total is a platform setting; contact Junis if your integration needs more.
</Tip>

***

## Rate Limit Headers

Every API response includes headers that show your current rate limit status.

### Response Headers

```http theme={null}
X-RateLimit-Limit-Minute: 100
X-RateLimit-Remaining-Minute: 55
X-RateLimit-Reset-Minute: 1767261600
X-RateLimit-Limit-Hour: 3000
X-RateLimit-Remaining-Hour: 2950
X-RateLimit-Reset-Hour: 1767261600
X-RateLimit-Limit-Org-Minute: 300
X-RateLimit-Remaining-Org-Minute: 240
```

| Header | Description |
| - | - |
| `X-RateLimit-Limit-Minute` | Maximum requests allowed per minute for this key |
| `X-RateLimit-Remaining-Minute` | Requests remaining for this key in the current minute window |
| `X-RateLimit-Reset-Minute` | Unix timestamp when the minute window resets |
| `X-RateLimit-Limit-Hour` | Maximum requests allowed per hour for this key |
| `X-RateLimit-Remaining-Hour` | Requests remaining for this key in the current hour window |
| `X-RateLimit-Reset-Hour` | Unix timestamp when the hour window resets |
| `X-RateLimit-Limit-Org-Minute` | Maximum requests per minute for all keys of your organization combined |
| `X-RateLimit-Remaining-Org-Minute` | Requests remaining for the whole organization in the current minute window (resets with the minute window) |

<Note>
  Responses also carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Window` without a suffix. Those belong to a platform-level flood guard in front of the key limiter and are not your key's quota — read the suffixed headers above.
</Note>

<Tip>
  Always monitor `X-RateLimit-Remaining-*` headers to avoid hitting rate limits. Consider pausing requests when remaining count is low.
</Tip>

***

## 429 Too Many Requests

When you exceed your rate limit, the API returns a `429` status code.

### Response Format

**HTTP Status**:

```
HTTP/1.1 429 Too Many Requests
Retry-After: 45
```

**Headers**:

```
X-RateLimit-Limit-Minute: 100
X-RateLimit-Remaining-Minute: 0
X-RateLimit-Reset-Minute: 1767261600
X-RateLimit-Limit-Hour: 3000
X-RateLimit-Remaining-Hour: 2950
X-RateLimit-Reset-Hour: 1767261600
X-RateLimit-Limit-Org-Minute: 300
X-RateLimit-Remaining-Org-Minute: 180
Retry-After: 45
```

**Body**:

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded: 100 requests per minute",
  "limit": 100,
  "window": "minute",
  "reset_at": 1767261600,
  "retry_after": 45
}
```

| Field | Description |
| - | - |
| `error` | Error type: `rate_limit_exceeded` |
| `message` | Human-readable error message |
| `limit` | The rate limit that was exceeded |
| `window` | Which window was exceeded: `minute`, `hour` (this key) or `org_minute` (all keys of the organization) |
| `reset_at` | Unix timestamp when the window resets |
| `retry_after` | Seconds to wait before retrying |

When the organization-wide total is exceeded, `window` is `org_minute`, `limit` is the organization total and `message` reads `Organization rate limit exceeded: 300 requests per minute across all API keys`. The per-key windows are checked first.

***

## Handling Rate Limits

### Best Practices

* **Monitor Headers**: Always check `X-RateLimit-Remaining-Minute`, `X-RateLimit-Remaining-Hour` and `X-RateLimit-Remaining-Org-Minute` headers to track your usage
* **Implement Exponential Backoff**: When you receive a 429 response, use the `Retry-After` header value to wait before retrying
* **Cache Responses**: Implement caching (TTL: 5 minutes recommended) to reduce API calls for frequently accessed data
* **Batch Requests**: Use paginated endpoints instead of individual requests (e.g., `GET /api/external/sessions?limit=100`)
* **Use Streaming**: For real-time chat, use `stream: true` parameter instead of polling to avoid repeated API calls

***

## Rate Limit Optimization

### Identify Bottlenecks

1. **Log Rate Limit Headers**: Track `X-RateLimit-Remaining-*` headers in your application logs
2. **Analyze Request Patterns**: Identify high-frequency endpoints that may benefit from caching or batching
   * Repeated session fetches → Add caching
   * Individual message fetches → Use paginated list endpoints
   * Polling for updates → Switch to streaming
3. **Implement Caching**: Use Redis or in-memory cache with 5-minute TTL for frequently accessed data
4. **Monitor & Alert**: Set up alerts when rate limit usage exceeds 90%

***

## Testing Rate Limits

### Local Testing

Test your rate limit handling before deploying to production:

```bash theme={null}
# Test the per-key minute limit (default 100 per minute — send 105 requests in 1 minute)
for i in {1..105}; do
  curl -s -o /dev/null -w "%{http_code}\n" \
    https://api.junis.ai/api/external/v1/chat/completions \
    -H "X-API-Key: jns_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"messages":[{"role":"user","content":"test"}]}'
  sleep 0.5
done
```

***

## Increasing Rate Limits

Per-key limits are stored on the key itself, so they can be changed without redeploying anything:

1. An organization admin calls `PUT /api/admin/api-keys/{key_id}` (JWT authentication) with `rate_limit_per_minute` (1–1,000) and/or `rate_limit_per_hour` (1–100,000).
2. The new values apply from the next request made with that key.

<Warning>
  Only organization admins can modify API key rate limits. Raising a key above the organization-wide total (300 requests per minute across all keys by default) does not add capacity on its own — the organization total still applies. Contact Junis to raise the organization total.
</Warning>

<Tip>
  Set rate limits based on your actual usage patterns. Start conservative and increase as needed.
</Tip>

***

## FAQs

<AccordionGroup>
  <Accordion title="Are rate limits per organization or per API key?" icon="question">
    **Answer**: Both. Each key has its own per-minute and per-hour limits, and all keys of the organization share one per-minute total (300 by default).

    Example: If your organization has 2 API keys:

    * API Key 1: 100 requests/minute
    * API Key 2: 100 requests/minute
    * Organization total: 300 requests/minute — the keys together can never exceed it, so adding a third key does not add capacity beyond the total
  </Accordion>

  <Accordion title="What happens if I exceed rate limits?" icon="question">
    **Response**: `429 Too Many Requests` with `Retry-After` header

    **Action**: Wait for the number of seconds specified in `Retry-After` or until the next window reset

    **No penalties**: No account suspension or additional charges
  </Accordion>

  <Accordion title="Can I request a temporary rate limit increase?" icon="question">
    **Per key**: Yes — an organization admin updates the key through the admin API (`PUT /api/admin/api-keys/{key_id}`), and the change applies from the next request

    **Organization total**: Contact Junis
  </Accordion>

  <Accordion title="Do streaming responses count differently?" icon="question">
    **Answer**: Streaming responses count as **1 request**, regardless of how long the stream lasts.

    **Example**:

    * Non-streaming: 1 request = 1 complete response
    * Streaming: 1 request = entire conversation stream

    Streaming is more efficient for real-time chat.
  </Accordion>

  <Accordion title="How do I monitor my rate limit usage?" icon="question">
    **Method 1**: Check response headers (`X-RateLimit-Remaining-*`)

    **Method 2**: Set up logging in your application (see Best Practices)

    **Method 3**: Monitor 429 error rates in your application metrics
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/api-reference/authentication">
    Learn about API keys and scopes
  </Card>

  <Card title="Error Codes" icon="triangle-exclamation" href="/api-reference/error-codes">
    Handle 429 and other API errors
  </Card>

  <Card title="Chat Completions API" icon="comments" href="/api-reference/chat-completions">
    Start building with streaming
  </Card>

  <Card title="Sessions API" icon="list" href="/api-reference/sessions">
    Manage chat sessions efficiently
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.