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

# SURCHI API Rate Limits and Quotas by Plan

> SURCHI API rate limits by tier — requests per minute, WebSocket connections, and data quotas. How to handle 429 errors and implement backoff.

The SURCHI Developer API enforces rate limits to ensure fair access and platform stability across all integrations. Limits are applied per API key on a rolling 60-second window. If your application exceeds its limit, subsequent requests will receive a `429 Too Many Requests` response until the window resets. This page covers limit tiers, the rate limit headers returned on every response, and how to implement graceful handling for limit errors.

## Rate Limit Tiers

Access tier is determined by your SURCHI token stake at the time of API key registration. Staking requirements and tier thresholds are defined in the protocol governance parameters.

| Tier         | Requests / min | WebSocket Connections | Historical Data | Access Requirement    |
| ------------ | -------------- | --------------------- | --------------- | --------------------- |
| **Explorer** | 60             | 1                     | 7 days          | Free                  |
| **Sentinel** | 300            | 3                     | 90 days         | Requires SURCHI stake |
| **Elite**    | 1,200          | 10                    | Full history    | Requires SURCHI stake |

**Explorer** is available to all approved developer accounts at no cost and is suitable for development, testing, and low-volume applications.

**Sentinel** and **Elite** tiers unlock higher throughput and extended historical data access in exchange for a SURCHI token stake. Staked tokens remain in your custody — they are not transferred to the protocol. Tier upgrades take effect within one epoch (approximately 24 hours) after your stake is confirmed on-chain.

## Rate Limit Headers

Every API response includes the following headers to help your application track consumption and anticipate resets:

| Header                  | Description                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------ |
| `X-RateLimit-Limit`     | The maximum number of requests allowed in the current window for your tier                       |
| `X-RateLimit-Remaining` | The number of requests remaining in the current 60-second window                                 |
| `X-RateLimit-Reset`     | Unix timestamp (seconds) at which the current window resets and the counter returns to the limit |

Example headers on a Sentinel-tier response:

```
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1705329660
```

When `X-RateLimit-Remaining` reaches `0`, the next request will return a `429` response. Your application can use these headers to implement proactive throttling rather than waiting for a rejection.

## Handling 429 Errors

When a `429 Too Many Requests` response is received, the response will also include a `Retry-After` header indicating how many seconds to wait before retrying. Always respect this value. The following TypeScript utility implements an automatic retry with exponential backoff as a fallback when `Retry-After` is not present:

```typescript retry.ts theme={null}
async function apiRequest(
  url: string,
  options: RequestInit,
  retries = 3
): Promise<Response> {
  const response = await fetch(url, options);

  if (response.status === 429 && retries > 0) {
    const retryAfter = response.headers.get('Retry-After') || '5';
    const delayMs = parseInt(retryAfter, 10) * 1000;

    console.warn(`Rate limited. Retrying in ${retryAfter}s... (${retries} retries left)`);
    await new Promise((resolve) => setTimeout(resolve, delayMs));

    return apiRequest(url, options, retries - 1);
  }

  return response;
}
```

For production applications, consider a more robust queue-based approach that tracks the `X-RateLimit-Remaining` header proactively and paces outgoing requests before hitting the limit, rather than relying on retry-after-rejection.

### 429 Response Body

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "error_description": "You have exceeded your request limit of 60 requests per minute. Upgrade to a Sentinel or Elite tier for higher limits.",
  "retry_after": 12,
  "status": 429
}
```

## WebSocket Rate Limits

WebSocket connections consume from a separate connection quota rather than the per-minute request limit. Sending subscription messages or receiving pushed events does not count against your REST request quota.

| Tier     | Max Concurrent Connections | Max Subscriptions per Connection |
| -------- | -------------------------- | -------------------------------- |
| Explorer | 1                          | 5                                |
| Sentinel | 3                          | 20                               |
| Elite    | 10                         | Unlimited                        |

Exceeding your connection quota causes the oldest connection to be terminated with close code `4029` (rate limit).

<Tip>
  Cache intelligence signals client-side. Most signals remain valid and actionable for at least **60 seconds** — polling the `/v1/intelligence/signals` endpoint more frequently than once per minute rarely provides additional value and burns through your request quota. For truly real-time use cases, use the WebSocket stream instead.
</Tip>
