Rate Limits
Dwellir rate limits by plan, token bucket algorithm with burst protection, handling 429 errors, and setting per-key usage quotas to control API spend.
Rate limits ensure fair usage and optimal performance for all users. Understanding and managing your rate limits is crucial for building reliable applications.
Rate Limits by Plan
| Features | Free | Developer | Growth | Scale |
|---|---|---|---|---|
| Price | Free | $49/mo | $299/mo | $999/mo |
| Overages | ✗ | $5/million | $3/million | $2/million |
| Responses per second | 20 | 100 | 500 | 5,000 |
| Responses per second (burst) | ✗ | 500 | 2,500 | 10,000 |
eth_getLogs block-range limits
These limits apply to each eth_getLogs request over HTTP and WebSocket, separately from responses-per-second limits.
| Plan | Maximum blocks per request |
|---|---|
| Free | Not available |
| Developer | 500 |
| Growth | 10,000 |
| Scale / Enterprise | 10,000 by default |
Both endpoint blocks count: toBlock - fromBlock + 1.
Individual networks may enforce lower limits. Range limits do not guarantee a maximum response size or execution time.
Burst protection does not increase these block limits.
Choose block bounds
Supply one filter object with block bounds, or use blockHash for a single block.
Do not combine a non-null blockHash with non-null block bounds.
Use hexadecimal block numbers. The earliest tag means block zero.
Missing or null bounds default to latest. An empty filter therefore requests one block.
A filter with only fromBlock scans toward latest and must fit the plan limit.
A filter with only numeric toBlock starts at latest. If toBlock is below the observed head, it returns -32602.
Equal tags, including latest, pending, safe, and finalized, also request one block where the network supports them.
Numeric ranges ending at latest or pending use the observed endpoint head plus a 6-block margin for validation.
The node receives the original tags. Use explicit numeric bounds when you need an exact range width.
Mixed ranges involving safe or finalized are rejected because their heights depend on the network.
This Developer request covers exactly 500 blocks, from 100 through 599:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_getLogs",
"params": [{"fromBlock": "0x64", "toBlock": "0x257"}]
}Changing toBlock to 0x258 requests 501 blocks and exceeds the Developer limit.
Address and topic filters do not increase the allowed range.
Split larger ranges
Resolve the ending height once with eth_blockNumber, then query consecutive numeric ranges within your plan limit.
For Developer, query blocks 100 through 599, then 600 through 1,099.
Continue from the previous toBlock + 1 to avoid gaps and overlap.
Reduce the chunk size if the network returns a stricter limit or a timeout.
See the pagination and backfill guide for a scanner example.
Handle range errors
Range validation errors return HTTP 200 with a JSON-RPC error body. Check the body even when the HTTP request succeeds.
| Condition | JSON-RPC code | Action |
|---|---|---|
| Range exceeds the plan limit | -32005 | Split the range within the limit named in the message. |
| Malformed or unmeasurable bounds | -32602 | Supply valid numeric bounds, equal tags, or a single-block hash. |
| Endpoint head unavailable for a tagged bound | -32000 | Retry shortly or use explicit numeric bounds. |
WebSocket returns the corresponding JSON-RPC error without closing the connection. These errors differ from HTTP 429 responses caused by request-rate limits. HTTP 413 indicates an oversized request body, not a block-range rejection.
The same range validation applies to eth_newFilter when your plan permits that method.
If any log query fails validation in a batch, the entire batch is rejected before forwarding.
No member executes, including other methods or transaction submissions in that batch.
Violating requests retain their error codes and IDs. Other requests with IDs receive -32000 indicating that the batch did not execute.
Notifications receive no JSON-RPC response. Rejected batches containing only notifications return HTTP 204.
Scope: Per Account, Not Per Key
Rate limits apply to your account as a whole. Every API key on an account draws from the same limit, so creating additional keys divides your existing budget rather than adding to it.
This surprises people often enough to be worth stating plainly:
| Assumption | Reality |
|---|---|
| A new key gets its own responses/second | All keys on the account share one limit |
| Splitting traffic across keys raises throughput | It does not — the ceiling is the account's |
| A new workload is isolated from production | It competes with production on the same account |
Why It Matters
Adding a workload to an account that already runs production traffic makes the two compete. A backfill, a new chain integration, or a long-lived gRPC subscription can exhaust the shared budget and throttle a service that was running comfortably before — with no change to that service at all.
This is most visible on streaming endpoints, where a single subscription can sustain a high message rate indefinitely. A new Aptos transaction stream and an existing Sui checkpoint subscription on the same account share one limit, and the noisier one will throttle the quieter one.
If two workloads must not compete, the limit is not something you can separate after the fact with a second key. Either run them on separate accounts, or size the plan for their combined peak rate before going live.
What You Can Still Scope Per Key
Per-key controls exist, but they cap spend rather than reserve throughput:
- Usage quotas — daily or monthly caps, set per key at dashboard.dwellir.com/api-keys. These stop a runaway workload from consuming the account's budget, which is the closest thing to isolation within a single account.
- Per-key analytics — attribute consumption to a workload at dashboard.dwellir.com/usage, so you can see which key is causing contention.
- Unlimited Nodes — a fixed requests-per-second tier dedicated to one endpoint, outside the shared account limit entirely.
Use quotas to bound the damage, separate accounts or an unlimited node to guarantee headroom.
Token Bucket Algorithm
Dwellir uses the token bucket algorithm for rate limiting, providing flexible and fair request handling with burst protection.
How It Works
The token bucket algorithm works like a bucket that:
- Holds tokens - Each token represents permission to make one request
- Has a maximum capacity - The bucket can hold up to your burst limit
- Refills at a constant rate - Tokens are added at your plan's responses/second rate
- Consumes tokens per request - Each API call removes one token
┌─────────────────────────┐
│ Token Bucket │
│ │
│ Capacity: 500 tokens │ ← Burst capacity
│ Current: 350 tokens │
│ Refill: 100 tokens/s │ ← Your plan's rate
│ │
└─────────────────────────┘
↓
API Response
(consumes 1 token)Benefits of Token Bucket
- Burst Handling - Handle traffic spikes gracefully
- Smooth Rate Limiting - No hard cutoffs at exact intervals
- Fair Usage - Unused capacity accumulates for later use
- Predictable Behavior - Easy to understand and plan for
Example Scenarios
Scenario 1: Steady Traffic
- Plan: Developer (100 responses/s)
- Usage: 80 responses/s consistently
- Result: ✅ All requests succeed, 20 tokens/s accumulate up to burst limit
Scenario 2: Traffic Burst
- Plan: Developer (100 responses/s, 500 burst capacity)
- Usage: 300 responses/s for 1 second
- Result: ✅ All requests succeed using burst tokens
- Recovery: Need to stay under 100 responses/s to refill
Scenario 3: Sustained Overuse
- Plan: Developer (100 responses/s)
- Usage: 150 responses/s sustained
- Result: ⚠️ After burst depletes, 50 responses/s are rate limited
Request Counting
What Counts as a Response?
Each of the following counts as 1 API response:
- Standard JSON-RPC calls (
eth_getBalance,eth_call, etc.) - Batch requests count as the number of calls in the batch
- WebSocket messages (both sent and received)
- Even trace and debug methods (no compute unit multipliers!)
- gRPC unary calls, and each message delivered on a gRPC stream
For streaming endpoints the billed unit is the message the server sends, not the
subscription. A Sui SubscribeCheckpoints subscription counts one per checkpoint
delivered; an Aptos GetTransactions stream counts one per TransactionsResponse
batch, including the progress-only messages a filtered stream emits. There is no
cap on concurrent subscriptions — the limit applies to the messages they deliver,
pooled across the account.
Handling Rate Limit Errors
When you exceed your rate limit, you'll receive a 429 HTTP status code with the following response:
{
"jsonrpc": "2.0",
"error": {
"code": -32005,
"message": "Rate limit exceeded"
},
"id": 1
}Setting Usage Limits
Protect yourself from unexpected charges by setting limits per API key:
- Go to dashboard.dwellir.com/api-keys
- Click the edit icon (✏️) next to your API key
- Set daily or monthly quotas
- Click "Update API Key" to save
When a quota is reached, the API will return a 429 error until the quota resets.
Monitoring Your Usage
Dashboard Analytics
Track your usage in real-time at dashboard.dwellir.com/usage:
- Current responses/second
- Daily and monthly usage
- Per-method breakdown
- Geographic distribution
API Access
For programmatic access to usage data, please contact our team.
Need Higher Limits?
If you need higher rate limits:
- Upgrade Your Plan - Check if a higher tier meets your needs
- Unlimited Nodes - Buy a fixed requests-per-second tier for one endpoint and stop consuming credits on it
- Contact Support - Request custom limits within your current plan
- Enterprise Solutions - Get custom infrastructure and limits
When requesting increases, provide:
- Current usage patterns
- Expected growth timeline
- Peak traffic requirements
- Use case description
Contact our team for custom rate limits.
Unlimited Node Pricing
Dwellir Unlimited Node pricing: a single RPC endpoint with unmetered requests at a fixed monthly price, with tiers from 25 to 1,000 requests per second and no overages.
Archive Nodes
Learn what archive nodes are, when you need them, how they differ from full nodes, and how to choose the right endpoint on Dwellir.