Skip to main content

Rate Limits

Rate Limits and Compute Unit Allocations by Plan
PlanMonthly CU PoolTrace CU PoolThroughput (CUPs)Chains
Starter400M CUsNo access50 CUs/sec17 (all)
Growth2B CUs100M330 CUs/sec17 (all)
Scale12B CUs1B1,250 CUs/sec17 (all)
EnterpriseCustom CUsCustomCustom CUs/sec17 (all)

CUPs (Compute Units Per Second): Maximum throughput rate. Average request = ~25 CUs, so 50 CUPs ≈ 2 requests/sec.

Monthly CU Pool: Total compute units available per month. Resets on billing cycle.

Trace CU Pool: Separate allocation for trace_* and debug_* methods (high-compute operations).

Understanding CU-Based Rate Limiting

Axol uses Compute Units (CUs) to measure API usage. This provides fair pricing where simple calls cost less than complex operations.

Two Types of Limits

  1. Throughput (CUPs): Maximum CUs per second. Controls request rate.
  2. Monthly CU Pool: Total CUs available per billing cycle. Controls volume.

Both limits work together:

  • CUPs prevent bursts that could overload infrastructure
  • Monthly pool ensures fair usage across billing period

Standard vs Trace CU Pools

Trace and debug methods consume 50-5000x more compute than standard calls. To prevent accidental overages, they use a separate CU pool:

  • Standard Pool: eth_, net_, web3_*, WebSocket subscriptions
  • Trace Pool: trace_, debug_ methods (Growth+ tiers only)

Monitoring Usage

Response Headers

Every API response includes rate limit headers:

X-RateLimit-CU-Limit: 2000000000
X-RateLimit-CU-Remaining: 1950000000
X-RateLimit-CU-Reset: 1704153600
X-RateLimit-Trace-CU-Limit: 100000000
X-RateLimit-Trace-CU-Remaining: 95000000
X-RateLimit-Trace-CU-Reset: 1704153600

Dashboard Monitoring

Access real-time usage at app.axol.io/dashboard:

  • Current month CU usage (standard + trace)
  • Projected overage cost
  • Historical usage charts
  • Cost breakdown by method

Handling Rate Limit Errors

429 Too Many Requests

When you exceed CUPs (throughput limit):

{
"error": "Rate limit exceeded",
"retryAfter": 2,
"cupsLimit": 330,
"currentCups": 350
}

Solution: Implement exponential backoff

import time
from axol import AxolClient, RateLimitError

client = AxolClient(api_key="YOUR_KEY")

def with_retry(func, *args, max_retries=3):
for attempt in range(max_retries):
try:
return func(*args)
except RateLimitError as e:
if attempt == max_retries - 1:
raise
wait_time = min(2 ** attempt, e.retry_after)
print(f"Rate limited. Waiting {wait_time}s...")
time.sleep(wait_time)

# Usage
result = with_retry(client.eth_call, "ethereum", {...})

402 CU Pool Exhausted

When you exceed monthly CU pool:

{
"error": "Monthly CU pool exhausted",
"cuLimit": 2000000000,
"cuUsed": 2000000000,
"resetDate": "2024-02-01T00:00:00Z",
"upgradeUrl": "https://app.axol.io/upgrade"
}

Options:

  1. Wait until billing cycle resets
  2. Enable overage billing (charged at $0.42/1M CUs)
  3. Upgrade to higher tier

Usage Alerts

Automatic email alerts sent at:

  • 80% usage: Warning notification
  • 90% usage: Urgent notification
  • 100% usage: Critical notification + throttling begins
  • 110% usage: Hard limit (or overage billing if enabled)

Configure alert preferences at app.axol.io/settings/alerts.

Optimization Tips

1. Cache Responses

Many blockchain queries return static data. Cache locally:

from functools import lru_cache

@lru_cache(maxsize=1000)
def get_block_cached(chain, block_number):
return client.get_block(chain, block_number)

2. Use Batch Endpoints

Batch multiple queries into single request:

# Bad: 100 separate requests = 100 * 15 = 1,500 CUs
balances = [client.eth_get_balance(addr) for addr in addresses]

# Good: 1 batch request = 100 * 15 = 1,500 CUs (same cost, but faster)
balances = client.batch_get_balances(addresses)

3. Avoid Trace Methods When Possible

MethodCU CostAlternativeCU Cost
debug_traceTransaction5,000eth_getTransactionReceipt15
trace_block2,500eth_getBlockReceipts250

Use trace methods only when you need detailed execution traces.

4. Optimize Log Queries

eth_getLogs cost scales with block range:

# Bad: Wide range = 500 CUs
logs = client.eth_get_logs(from_block=0, to_block="latest")

# Good: Narrow range = 75 CUs
logs = client.eth_get_logs(from_block=19000000, to_block=19001000)

5. Monitor High-CU Methods

Track which methods consume most CUs:

import logging

logging.basicConfig(level=logging.INFO)

# Logs CU cost per request
client = AxolClient(api_key="YOUR_KEY", log_cu_usage=True)

Troubleshooting

High CU Usage

If you're consuming CUs faster than expected:

  1. Check method distribution: Are you using trace methods?
  2. Review log queries: Wide block ranges inflate costs
  3. Audit batch sizes: Extremely large batches may hit limits
  4. Check WebSocket subscriptions: Each event costs 40 CUs

Trace Pool Exhaustion

If you exhaust trace CU pool before standard pool:

  1. Optimize trace usage: Use only when necessary
  2. Cache trace results: Traces for same tx don't change
  3. Consider Scale tier: 10x larger trace pool (1B vs 100M CUs)
  4. Use debug methods selectively: debug_traceTransaction costs 5,000 CUs

Unexpected Throttling

If you're throttled despite available CUs:

  1. Check CUPs limit: You may hit throughput before volume limit
  2. Spread requests over time: Don't burst all requests at once
  3. Implement rate limiting: Client-side throttling prevents 429s
from axol import AxolClient
import time

client = AxolClient(api_key="YOUR_KEY")

# Respect CUPs limit (e.g., 330 CUPs for Growth tier)
cups_limit = 330
avg_cu_per_request = 25
max_requests_per_second = cups_limit / avg_cu_per_request # ~13 req/s

for i in range(100):
client.eth_block_number("ethereum")
if i % max_requests_per_second == 0:
time.sleep(1) # Throttle to stay under limit

Next Steps