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

# Rate limits

> Check your plan's request limits, read rate-limit response headers, and handle 429 responses with a retry strategy.

Every API key is rate limited by plan tier. Use the response headers to track your remaining capacity, and back off when you receive a `429 Too Many Requests` response.

## Limits by plan

| Plan | Sustained rate |
| - | - |
| **Standard** | 100 requests/sec |
| **Pro** | 1,000+ requests/sec |
| **Enterprise** | Custom |

For what else differs by plan, see [Plans](/documentation/plans-limits/plans-tiers). Need more capacity? [Contact us](mailto:hello@yield.xyz) to upgrade.

## Rate limit headers

Limits are counted per API key in fixed 60-second windows (for example, 6,000 requests per window on Standard). Every API response includes headers that report your current rate-limit status:

```
x-ratelimit-limit: 6000
x-ratelimit-remaining: 5995
x-ratelimit-reset: 1698765432
```

| Header | Description |
| - | - |
| `x-ratelimit-limit` | Request limit per 60-second window |
| `x-ratelimit-remaining` | Requests remaining in the current window |
| `x-ratelimit-reset` | Unix timestamp (seconds) when the window resets |
| `retry-after` | Seconds to wait before retrying; sent only when you are rate limited |

## Handling 429 responses

When you exceed your limit, the API returns `429 Too Many Requests` with the wait time in seconds:

```json theme={null}
{
  "message": "Rate limit exceeded",
  "error": "Too Many Requests",
  "statusCode": 429,
  "retryAfter": 3
}
```

Respect the `retry-after` header and add exponential backoff so retries don't pile up:

```typescript theme={null}
async function fetchWithRetry(
  url: string,
  options: RequestInit,
  maxRetries = 3
): Promise<Response> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = response.headers.get('retry-after') || '5';
      const waitTime = parseInt(retryAfter) * 1000 * Math.pow(2, attempt);

      console.log(`Rate limited. Retrying in ${waitTime / 1000}s...`);
      await new Promise(r => setTimeout(r, waitTime));
      continue;
    }

    return response;
  }

  throw new Error('Max retries exceeded');
}
```

## Reducing request volume

Most rate-limit pressure comes from avoidable calls. Cache stable data, batch lookups, and queue bursts.

> **Cache yield metadata**
>
> Yield metadata (APY, TVL, validators) changes infrequently. Cache it for 5 to 15 minutes:
>
> ```typescript theme={null}
> const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
> const cache = new Map();
>
> async function getYields() {
>   const cached = cache.get('yields');
>   if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
>     return cached.data;
>   }
>
>   const response = await fetch('https://api.yield.xyz/v1/yields');
>   const data = await response.json();
>   cache.set('yields', { data, timestamp: Date.now() });
>   return data;
> }
> ```

> **Use aggregate endpoints**
>
> Instead of one balance request per address and yield, send 1 to 25 queries in a single `POST /v1/yields/balances` request. See [Get aggregate balances](/api-reference/YieldsController_getAggregateBalances).
>
> ```bash theme={null}
> POST /v1/yields/balances
> {
>   "queries": [
>     { "address": "0x...", "network": "ethereum", "yieldId": "ethereum-eth-lido-staking" },
>     { "address": "0x...", "network": "ethereum", "yieldId": "ethereum-eth-reth-staking" }
>   ]
> }
> ```

> **Queue requests during bursts**
>
> Throttle outgoing requests to stay under your plan's sustained rate:
>
> ```typescript theme={null}
> class RequestQueue {
>   private queue: (() => Promise<any>)[] = [];
>   private processing = false;
>   private requestsPerSecond = 100; // match your plan tier
>
>   async add<T>(fn: () => Promise<T>): Promise<T> {
>     return new Promise((resolve, reject) => {
>       this.queue.push(async () => {
>         try {
>           resolve(await fn());
>         } catch (e) {
>           reject(e);
>         }
>       });
>       this.process();
>     });
>   }
>
>   private async process() {
>     if (this.processing) return;
>     this.processing = true;
>
>     while (this.queue.length > 0) {
>       const fn = this.queue.shift()!;
>       await fn();
>       await new Promise(r =>
>         setTimeout(r, 1000 / this.requestsPerSecond)
>       );
>     }
>
>     this.processing = false;
>   }
> }
> ```

## Next steps

> **[Plans and pricing](/documentation/plans-limits/plans-tiers)**
>
> Compare rate limits, vault deployments and what each plan covers.

> **[Errors and retries](/api-reference/errors-retries)**
>
> Status codes and retry guidance for every API.


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