Rate Limit Handling
Limits
- Standard: 100 requests/minute per wallet
- Premium: 1000 requests/minute per wallet
- Cached responses (30s) do NOT count toward limit
- Free endpoints do NOT count
Retry with Exponential Backoff
import time
import httpx
def request_with_retry(url, max_retries=3):
for attempt in range(max_retries):
response = client.get(url)
if response.status_code != 429:
return response.json()
wait = 2 ** attempt # 1s, 2s, 4s
print(f"Rate limited. Retry in {wait}s...")
time.sleep(wait)
raise Exception("Max retries exceeded")
Queue-Based Approach (Async)
import asyncio
class RateLimitedQueue:
def __init__(self, rpm=100):
self.interval = 60.0 / rpm
self.semaphore = asyncio.Semaphore(1)
async def fetch(self, url):
async with self.semaphore:
result = await client.aget(url)
await asyncio.sleep(self.interval)
return result
# Usage
queue = RateLimitedQueue(rpm=90) # Use 90 to stay under 100
results = await asyncio.gather(*[
queue.fetch(f"https://api.foursec.xyz/price/{s}")
for s in ['ETH', 'BTC', 'SOL']
])
Sliding Window Counter
import time
from collections import deque
class SlidingWindowLimiter:
def __init__(self, max_requests=90, window=60):
self.max_requests = max_requests
self.window = window
self.requests = deque()
def can_request(self):
now = time.time()
# Remove old requests outside window
while self.requests and self.requests[0] < now - self.window:
self.requests.popleft()
if len(self.requests) < self.max_requests:
self.requests.append(now)
return True
return False
def wait_time(self):
if not self.requests:
return 0
oldest = self.requests[0]
return max(0, oldest + self.window - time.time())
# Usage
limiter = SlidingWindowLimiter(max_requests=90, window=60)
def safe_request(url):
while not limiter.can_request():
time.sleep(limiter.wait_time())
return client.get(url).json()
Multiple Wallets (Load Balancing)
For high-throughput needs, rotate across multiple wallets:
from itertools import cycle
wallets = [
Account.from_key("0x_key1"),
Account.from_key("0x_key2"),
Account.from_key("0x_key3"),
]
wallet_cycle = cycle(wallets)
def get_next_client():
wallet = next(wallet_cycle)
return X402Client(wallet=wallet)
# Each wallet has its own 100 req/min limit
# 3 wallets = 300 req/min effective throughput