Rate limits
Rate limiting is a token bucket per account. This page explains how it refills, how batches count, and how to handle a 429 correctly.
How the limiter works
The bucket is per account, not per API key, creating more keys does not add throughput. Every key on your account draws from the same bucket, across all chains combined.
An advanced API key policy can add a lower key-wide sustained ceiling, and a verified JWT can add a lower per-token ceiling. The gateway checks every applicable bucket atomically. These delegated ceilings can only reduce throughput and never multiply the parent account limit. Key and token burst capacity is the smaller of the parent burst or five times the sustained method rate. A per-token bucket is identified by the API key ID plus the SHA-256 digest of the byte-exact JWS signing input: base64url(protected header).base64url(payload). This is neither the decoded claims nor the full compact JWT. Excluding the signature prevents equivalent ES256 high-S and low-S signatures from creating separate buckets. See API key security.
The bucket refills at your plan's sustained rate and holds at most the burst capacity in the live catalog. A full bucket lets you send that many method calls after an idle period, whether separately or in batches, then sustain the listed rate. An HTTP request gets a 429 when its methods need more tokens than the bucket currently holds.
Limits by plan
| Plan | Sustained | Burst capacity |
|---|---|---|
| Free | 2 RPC method calls/s | 10 calls |
| Builder | 120 RPC method calls/s | 600 calls |
| Solid | 600 RPC method calls/s | 3,000 calls |
| Rocksolid | 6,000 RPC method calls/s | 30,000 calls |
| Enterprise | Custom | Custom |
How batches count
A batch needs one token per method call, all at once. A batch of 100 method calls needs 100 tokens available at that moment, if the bucket holds fewer, the whole batch gets 429, not a partial result. Keep batch sizes below your burst capacity. Batching requires an API key: the keyless public endpoints accept one JSON-RPC call per HTTP request.
The 429 response
A rate-limited request returns HTTP 429 with how many tokens it needed and how many were available:
{
"error": "Rate limit exceeded",
"requiredTokens": 1,
"availableTokens": 0
}A recoverable 429 also includes the wait time:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
X-RateLimit-Limit: 120
X-RateLimit-Burst: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 5Rate-limited method calls are never billed or counted toward quota.
Response headers
Authenticated responses expose the state of both account-wide limits. Values are snapshots taken while the request is handled.
The example below uses the current Builder catalog limits with one response unit consumed.
X-RateLimit-Limit: 120
X-RateLimit-Burst: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 1
X-Quota-Limit: 10000000
X-Quota-Used: 1
X-Quota-Remaining: 9999999
X-Quota-Reset: 3600
X-Quota-Window: month| Header | Meaning |
|---|---|
X-RateLimit-Limit | Sustained token refill rate per second |
X-RateLimit-Burst | Maximum tokens the bucket can hold |
X-RateLimit-Remaining | Whole tokens available after this request |
X-RateLimit-Reset | Seconds until the bucket is full if traffic stops |
X-Quota-Limit | Included response units in the active quota window |
X-Quota-Used | Billable response units used in the active window |
X-Quota-Remaining | Included response units left, clamped to zero during overage |
X-Quota-Reset | Seconds until the daily or monthly quota resets |
X-Quota-Window | day or month, as listed for the active plan |
During a rate-limit server outage, unrestricted legacy keys keep the existing per-pod fallback. A configured key or token with a hard delegated method-rate ceiling returns HTTP 503 when that ceiling cannot be enforced globally. The gateway never silently widens a configured security policy.
Handling 429s
When Retry-After is present, wait at least that many seconds, then retry with exponential backoff plus jitter. If a batch needs more tokens than X-RateLimit-Burst, the gateway omits Retry-After because waiting cannot make it fit, split the batch. A 402 is a quota problem, not a rate problem, see pricing and overage billing.
viem's http transport retries failed requests by default, tune retryCount and retryDelay for your traffic:
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({
chain: mainnet,
transport: http("https://rpc.solidrpc.io/YOUR_API_KEY/evm/1", {
retryCount: 5,
retryDelay: 200,
}),
});ethers v6 does not auto-retry 429s, wrap calls in your own backoff if you use ethers.
If you see sustained 429s at your expected traffic level, you need the next plan, backoff only smooths spikes, it does not create throughput.