Quick lookup tables and decision trees for choosing the right bex router tier and staying within limits.
π Tier Comparison at a Glanceβ
| Tier | RPS | IP Limit | Best For | Monthly Price* |
|---|---|---|---|---|
| FREE | 1 | Development, testing | Free | |
| BASIC | 10 | Small apps | $ | |
| PRO | 10 | Production apps | $$ | |
| ENTERPRISE_50 | 50 | High-traffic apps | $$$ | |
| ENTERPRISE_500 | 500 | Mission-critical | Contact us |
Note: RPS is enforced per user (shared across all access keys), not per access key.
*See pricing page for current rates
π― Which Tier Do I Need?β
Decision Treeβ
How many requests per second do you need?
β
ββ Less than 1 req/s
β ββ Do you need to bypass IP restrictions?
β ββ No β <ion-icon name="checkmark-circle" style={{verticalAlign: "middle", fontSize: "1.2em", color: "#10b981"}}></ion-icon> FREE tier
β ββ Yes β <ion-icon name="checkmark-circle" style={{verticalAlign: "middle", fontSize: "1.2em", color: "#10b981"}}></ion-icon> BASIC tier
β
ββ Between 1-10 req/s
β ββ Do you need priority support?
β ββ No β <ion-icon name="checkmark-circle" style={{verticalAlign: "middle", fontSize: "1.2em", color: "#10b981"}}></ion-icon> BASIC tier
β ββ Yes β <ion-icon name="checkmark-circle" style={{verticalAlign: "middle", fontSize: "1.2em", color: "#10b981"}}></ion-icon> PRO tier
β
ββ Between 10-50 req/s
β ββ <ion-icon name="checkmark-circle" style={{verticalAlign: "middle", fontSize: "1.2em", color: "#10b981"}}></ion-icon> ENTERPRISE_50 tier
β
ββ More than 50 req/s
ββ <ion-icon name="checkmark-circle" style={{verticalAlign: "middle", fontSize: "1.2em", color: "#10b981"}}></ion-icon> ENTERPRISE_500 tier or customBy Use Caseβ
| Use Case | Recommended Tier | Why |
|---|---|---|
| Local development | FREE | Cost-effective, sufficient for testing |
| Hobby project | FREE or BASIC | Low traffic, minimal cost |
| Startup MVP | BASIC or PRO | Room to grow, professional support |
| Production DApp | PRO or ENTERPRISE_50 | Reliable, scalable |
| DEX / High-frequency | ENTERPRISE_500 | Maximum throughput |
| Analytics platform | ENTERPRISE_50/500 | Sustained high RPS |
| Wallet application | PRO or ENTERPRISE_50 | Depends on user base |
| NFT marketplace | ENTERPRISE_50 | Burst traffic handling |
π¦ Rate Limit Behaviorβ
FREE Tier: Dual Limits (AND Logic)β
Request arrives
β
Check User RPS (1 req/s) ββββ FAIL β 429 Too Many Requests
β PASS
β
Check IP RPS (1 req/s) ββββ FAIL β 429 Too Many Requests
β PASS
β
Process Request β 200 OKKey Point: Both limits must pass for FREE tier.
Paid Tiers: Single Limitβ
Request arrives
β
Check User RPS (tier-specific) ββββ FAIL β 429 Too Many Requests
β PASS
β
Process Request β 200 OKKey Point: No IP-based restrictions on paid tiers.
π Scaling Strategiesβ
Vertical Scaling (Upgrade Tier)β
| Current Tier | Next Tier | RPS Increase | IP Restriction Removed |
|---|---|---|---|
| FREE β BASIC | +9 req/s | 1 β 10 | |
| BASIC β PRO | 0 req/s | 10 β 10 | Already removed |
| PRO β ENTERPRISE_50 | +40 req/s | 10 β 50 | Already removed |
| ENTERPRISE_50 β ENTERPRISE_500 | +450 req/s | 50 β 500 | Already removed |
Horizontal Scaling (Multiple Keys)β
| Strategy | Setup | Total RPS | Cost |
|---|---|---|---|
| 1 FREE key | Simple | 1 | Free |
| 3 FREE keys | Key rotation | 3 | Free |
| 1 BASIC key | Simple | 10 | $ |
| 3 BASIC keys | Key rotation | 30 | $$$ |
| 1 ENTERPRISE_50 | Simple | 50 | $$$ |
Note: Using multiple keys requires key rotation logic in your application.
β‘ Request Budget Calculatorβ
FREE Tierβ
| Scenario | Math | Daily Requests |
|---|---|---|
| Constant rate at limit | 1 req/s Γ 86,400s | 86,400 |
| Constant rate at 50% | 0.5 req/s Γ 86,400s | 43,200 |
| Bursts (1 req every 1s) | Averages to 1 req/s | 86,400 |
BASIC/PRO Tierβ
| Scenario | Math | Daily Requests |
|---|---|---|
| Constant rate at limit | 10 req/s Γ 86,400s | 864,000 |
| Constant rate at 50% | 5 req/s Γ 86,400s | 432,000 |
ENTERPRISE_50 Tierβ
| Scenario | Math | Daily Requests |
|---|---|---|
| Constant rate at limit | 50 req/s Γ 86,400s | 4,320,000 |
| Constant rate at 50% | 25 req/s Γ 86,400s | 2,160,000 |
ENTERPRISE_500 Tierβ
| Scenario | Math | Daily Requests |
|---|---|---|
| Constant rate at limit | 500 req/s Γ 86,400s | 43,200,000 |
| Constant rate at 50% | 250 req/s Γ 86,400s | 21,600,000 |
Important: These are RPS limits. Your daily quota (compute units) may be lower. Check both limits in your dashboard.
π§ Common Optimization Scenariosβ
Scenario 1: Getting 429 on FREE Tierβ
Symptoms:
Response: 429 Too Many Requests
Current RPS: ~2 requests/second
Tier: FREEDiagnosis: Exceeding 1 req/s user limit
Solutions (ranked by effort):
- β‘ Add client-side throttling β Immediate
- β‘ Implement request queuing β 1-2 hours
- π° Upgrade to BASIC tier β Instant (10x RPS)
- π§ Batch requests β 2-4 hours of refactoring
Scenario 3: Need to Handle Spikesβ
Symptoms:
Normal traffic: 30 req/s
Peak traffic: 200 req/s (during NFT drops, events)
Current tier: ENTERPRISE_50 (50 req/s)Solutions:
- π° Upgrade to ENTERPRISE_500 β Instant
- π§ Implement request queue + retry logic β 1 day
- π§ Use multiple access keys with load balancing β 2 days
- π° Contact sales for burst pricing β Custom
Scenario 4: Multi-Region Applicationβ
Symptoms:
Users: Global (US, EU, Asia)
Requirements: Low latency, high availability
Current setup: Single key, single regionSolutions:
- π§ Use multiple regional keys β 1 day
- π° Enterprise plan with multi-region β Contact sales
- π§ Implement geo-based key selection β 2 days
π Error Response Cheat Sheetβ
| Status | Error | Cause | Immediate Fix | Long-term Fix |
|---|---|---|---|---|
| 401 | Unauthorized | Missing/invalid key | Check URL format | Regenerate key in dashboard |
| 403 | Forbidden | IP blocked | Contact support | Review traffic patterns |
| 429 | Too Many Requests | RPS limit exceeded | Wait 1 second | Add rate limiting |
| 429 | Too Many Requests | Quota exceeded | Wait until tomorrow | Upgrade plan or optimize |
π Implementation Cheat Sheetβ
Minimal Rate Limiter (JavaScript)β
// Simple delay-based limiter
class SimpleLimiter {
constructor(rps) {
this.delay = 1000 / rps;
this.lastCall = 0;
}
async wait() {
const now = Date.now();
const timeSinceLastCall = now - this.lastCall;
if (timeSinceLastCall < this.delay) {
await new Promise((r) => setTimeout(r, this.delay - timeSinceLastCall));
}
this.lastCall = Date.now();
}
}
// Usage (BASIC tier = 10 RPS)
const limiter = new SimpleLimiter(10);
async function makeRequest(url) {
await limiter.wait();
return fetch(url);
}Production Rate Limiter (TypeScript)β
// Sliding window limiter with queue
class ProductionLimiter {
private queue: Array<{ timestamp: number; resolve: () => void }> = [];
private processing = false;
constructor(
private rps: number,
private windowMs: number = 1000,
) {}
async acquire(): Promise<void> {
return new Promise((resolve) => {
this.queue.push({ timestamp: Date.now(), resolve });
this.processQueue();
});
}
private processQueue() {
if (this.processing) return;
this.processing = true;
const process = () => {
if (this.queue.length === 0) {
this.processing = false;
return;
}
const now = Date.now();
const windowStart = now - this.windowMs;
// Remove old entries
this.queue = this.queue.filter((item) => item.timestamp > windowStart);
// Check if we can process the next request
if (this.queue.length <= this.rps) {
const item = this.queue.shift()!;
item.resolve();
setTimeout(process, this.windowMs / this.rps);
} else {
setTimeout(process, 100); // Check again soon
}
};
process();
}
}
// Usage
const limiter = new ProductionLimiter(50); // ENTERPRISE_50
async function makeRequest(url: string) {
await limiter.acquire();
return fetch(url);
}Batch Request Helperβ
// Automatically batches JSON-RPC requests
class BatchHelper {
constructor(url, maxBatchSize = 10, flushIntervalMs = 100) {
this.url = url;
this.maxBatchSize = maxBatchSize;
this.flushIntervalMs = flushIntervalMs;
this.pendingRequests = [];
this.timer = null;
}
request(method, params) {
return new Promise((resolve, reject) => {
this.pendingRequests.push({
method,
params,
resolve,
reject,
id: Date.now() + Math.random(),
});
if (this.pendingRequests.length >= this.maxBatchSize) {
this.flush();
} else if (!this.timer) {
this.timer = setTimeout(() => this.flush(), this.flushIntervalMs);
}
});
}
async flush() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
if (this.pendingRequests.length === 0) return;
const batch = this.pendingRequests.splice(0, this.maxBatchSize);
const payload = batch.map((req) => ({
jsonrpc: "2.0",
id: req.id,
method: req.method,
params: req.params,
}));
try {
const response = await fetch(this.url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
const results = await response.json();
results.forEach((result) => {
const req = batch.find((r) => r.id === result.id);
if (req) {
if (result.error) {
req.reject(result.error);
} else {
req.resolve(result.result);
}
}
});
} catch (error) {
batch.forEach((req) => req.reject(error));
}
}
}
// Usage
const batcher = new BatchHelper("https://api.bex.co/eth/YOUR_KEY");
// These 3 calls will be batched into 1 HTTP request
const [block1, block2, block3] = await Promise.all([
batcher.request("eth_getBlockByNumber", ["0x1", false]),
batcher.request("eth_getBlockByNumber", ["0x2", false]),
batcher.request("eth_getBlockByNumber", ["0x3", false]),
]);π Quick Support Matrixβ
| Issue | Severity | FREE | BASIC | PRO | ENTERPRISE_50 | ENTERPRISE_500 |
|---|---|---|---|---|---|---|
| Rate limit questions | Low | Community/Docs | Email 48h | Email 24h | Email 12h | Phone/Slack |
| Account issues | Medium | Email 72h | Email 48h | Email 24h | Email 12h | Phone 2h |
| Service outage | High | Status page | Email 24h | Email 12h | Email 4h | Phone 1h |
| Custom integration | - | Not available | Email quote | Priority queue | Dedicated engineer | White-glove |
Contact:
- Community: Discord
- Email: hello@bex.co
- Sales: hello@bex.co
- Emergency (Enterprise only): [Your dedicated contact]
See also: