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

# Rate Limiting

> Account-wide RPS and shared compute units across API keys, 429 handling, and backoff strategies.

## Overview

BlockDB enforces **account-wide** limits so traffic stays fair and the platform remains stable. Your subscription defines a **single requests-per-second (RPS) ceiling** and a **single compute unit (CU) usage allowance** for the billing period. Those limits are **shared by every API key** on the account: there is **no** per-key RPS budget, **no** per-key CU pool, and **no** way to split or “distribute” rate or usage across keys.

<Info>
  Rate limiting is measured in **requests per second (RPS)**. [`GET /usage`](/api-reference/account-and-usage/usage) returns `rate_limit_rps` and your **CU** fields (`cu_used`, `cu_limit`, `cu_remaining`) for the **account**—the same values apply no matter which of your keys (up to five) you use.
</Info>

<Warning>
  Using multiple API keys does **not** multiply your RPS or your monthly CU budget. If two services each send traffic at the account RPS cap, they contend for the same shared limit. Plan concurrency and backoff accordingly.
</Warning>

## API keys and shared limits

You can create up to **five** keys in **[dashboard.blockdb.io](https://dashboard.blockdb.io)** for **rotation** (old vs new), **separate environments** (e.g. staging vs production in your own systems), or **blast-radius control** (revoke one key without rotating everything). Those are operational choices—**not** a mechanism to assign different RPS or CU to each key. BlockDB does not offer per-key rate or usage allocation.

```bash Example: two keys, one shared account limit theme={null}
# Both keys authenticate different callers but draw from the same RPS and CU pool.
Authorization: Bearer $BLOCKDB_API_KEY_PROD
Authorization: Bearer $BLOCKDB_API_KEY_STAGING
# Shared: rate_limit_rps and monthly CU (see /usage)
```

## Rate Limit Responses

### 429 Too Many Requests

When you exceed your rate limit, the API returns `429` with a `Retry-After` header:

```json Error theme={null}
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded",
    "details": "Limit: <CONFIGURED_RPS> requests/second. Retry after: <RETRY_AFTER>"
  }
}
```

## Backoff Strategies

### Exponential Backoff

Implement exponential backoff when receiving `429` responses:

<CodeGroup>
  ```csharp C# theme={null}
  using System;
  using System.Net.Http;
  using System.Threading.Tasks;

  public static async Task<HttpResponseMessage> RequestWithBackoffAsync(
      HttpClient client,
      Func<HttpRequestMessage> requestFactory,
      int maxRetries = 5)
  {
      var delay = TimeSpan.FromSeconds(1);

      for (var attempt = 0; attempt < maxRetries; attempt++)
      {
          using var request = requestFactory();
          var response = await client.SendAsync(request);

          if (response.StatusCode == (System.Net.HttpStatusCode)429)
          {
              var retryAfterHeader = response.Headers.RetryAfter?.Delta ?? delay;
              await Task.Delay(retryAfterHeader);
              delay = retryAfterHeader;
              continue;
          }

          if (response.IsSuccessStatusCode || attempt == maxRetries - 1)
          {
              return response;
          }

          await Task.Delay(delay);
          delay = TimeSpan.FromMilliseconds(delay.TotalMilliseconds * 2);
      }

      throw new InvalidOperationException("Retries exhausted");
  }
  ```

  ```cpp C++ theme={null}
  #include <chrono>
  #include <thread>
  #include <stdexcept>
  #include "http_client.h" // Replace with your preferred HTTP client wrapper

  HttpResponse requestWithBackoff(const HttpRequest& request, int maxRetries = 5) {
      using namespace std::chrono_literals;
      auto delay = 1s;

      for (int attempt = 0; attempt < maxRetries; ++attempt) {
          HttpResponse response = HttpClient::Send(request);

          if (response.status == 429) {
              auto retryAfter = response.headers.count("Retry-After")
                  ? std::chrono::seconds(std::stoi(response.headers.at("Retry-After")))
                  : delay;
              std::this_thread::sleep_for(retryAfter);
              delay = retryAfter;
              continue;
          }

          if (response.status < 500 || attempt == maxRetries - 1) {
              return response;
          }

          std::this_thread::sleep_for(delay);
          delay *= 2;
      }

      throw std::runtime_error("Retries exhausted");
  }
  ```

  ```python Python theme={null}
  import time
  import requests

  def request_with_backoff(url, headers, data, max_retries=5):
      delay = 1  # Start with 1 second
      
      for attempt in range(max_retries):
          try:
              response = requests.post(url, headers=headers, json=data)
              
              if response.status_code == 429:
                  retry_after = int(response.headers.get('Retry-After', delay))
                  time.sleep(retry_after)
                  delay = retry_after
                  continue
              
              return response
          except Exception as e:
              if attempt == max_retries - 1:
                  raise
              delay *= 2  # Exponential backoff
              time.sleep(delay)
  ```

  ```javascript Node.js theme={null}
  async function requestWithBackoff(url, options, maxRetries = 5) {
    let delay = 1000; // Start with 1 second
    
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      try {
        const response = await fetch(url, options);
        
        if (response.status === 429) {
          const retryAfter = parseInt(response.headers.get('Retry-After') || delay / 1000);
          delay = retryAfter * 1000;
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
        
        return response;
      } catch (error) {
        if (attempt === maxRetries - 1) throw error;
        delay *= 2; // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }
  ```
</CodeGroup>

## Best Practices

<Tip>
  Implement request queuing for high-volume applications to smooth out request patterns.
</Tip>

<Warning>
  Do not ignore `429` responses or retry immediately. Always respect the `Retry-After` header to avoid further rate limiting.
</Warning>

## Performance Expectations

When staying within your rate limits, typical **Historic REST API** response times look like:

* **Mean (average)**: 300-500 ms
* **p99**: around 900 ms

<Info>
  Figures are indicative and vary by endpoint, payload size, and region. Latency targets assume you're staying within your configured RPS limits. Sustained over-limit traffic may experience higher latency and eventual rate limiting.
</Info>

## Latency and routing (not separate quotas)

BlockDB may route you to a nearby edge or region for **lower latency** (for example via GeoDNS). That routing does **not** create separate RPS or CU pools per region or per key. Your **account** RPS and CU limits always apply the same way.

## Key rotation and dashboard

In **[dashboard.blockdb.io](https://dashboard.blockdb.io)** you can create, label, and revoke keys (up to five active). You **cannot** assign a different RPS or CU cap to an individual key—limits stay at the **account** level. Use [`GET /usage`](/api-reference/account-and-usage/usage) to monitor `rate_limit_rps` and **CU** usage for the whole account, not per key.

<Warning>
  Keep API keys secure and never commit them to version control. Rotate keys regularly for security best practices.
</Warning>

## See Also

* [Authorization](/api-reference/overview/authorization) — API keys and `Authorization: Bearer`
* [Usage & Limits](/api-reference/account-and-usage/usage) — `rate_limit_rps` and shared CU for your account
* [Compute units](/api-reference/overview/compute-units) - CU cost tiers (L1–L8) per endpoint family
* [Error Codes](/api-reference/overview/error-codes) - Complete error reference
* [Service Limits](/troubleshooting/service-limits/home) - Detailed quota information
