Complete API documentation for the Ethereum RPC Load Balancer.
These endpoints are publicly accessible and do not require authentication.
The main proxy endpoint that forwards JSON-RPC requests to backend Ethereum providers.
Endpoint: POST /
Headers:
Content-Type: application/jsonRequest Body:
{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}Response (200 OK):
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x12a4b7c"
}Supported Methods:
eth_blockNumber- Get latest block numbereth_getBlockByNumber- Get block by number (cacheable)eth_getBlockByHash- Get block by hash (cacheable)eth_getTransactionByHash- Get transaction by hash (cacheable)eth_getTransactionReceipt- Get transaction receipt (cacheable)eth_call- Execute call (not cacheable)eth_estimateGas- Estimate gas (not cacheable)eth_gasPrice- Get current gas price (not cacheable)eth_getBalance- Get account balanceeth_getCode- Get contract codeeth_getLogs- Get event logs- And all other standard Ethereum JSON-RPC methods
Caching Behavior:
- Requests with
"latest"parameter are never cached - Finalized blocks (>64 blocks old) are cached indefinitely
- Recent blocks (within 64 blocks) are cached for 5 minutes
- Unfinalized blocks are cached for 30 seconds
Error Responses:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "All providers are currently unavailable"
}
}Get statistics about all configured providers.
Endpoint: GET /providers
Response (200 OK):
{
"providers": [
{
"id": "infura",
"url": "https://mainnet.infura.io/v3/YOUR_KEY",
"healthy": true,
"weight": 85.2,
"requestCount": 1523,
"errorCount": 3,
"avgLatencyMs": 142,
"lastHealthCheck": "2025-10-14T10:29:45Z",
"circuitBreakerState": "closed"
},
{
"id": "alchemy",
"url": "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
"healthy": true,
"weight": 92.8,
"requestCount": 1687,
"errorCount": 1,
"avgLatencyMs": 128,
"lastHealthCheck": "2025-10-14T10:29:45Z",
"circuitBreakerState": "closed"
}
],
"totalProviders": 2,
"healthyProviders": 2,
"routingStrategy": "weighted"
}Response Fields:
id- Provider identifierurl- RPC endpoint URL (API keys masked)healthy- Current health statusweight- Current routing weight (higher = more traffic)requestCount- Total requests sent to this providererrorCount- Total error countavgLatencyMs- Average response time in millisecondslastHealthCheck- Timestamp of last health checkcircuitBreakerState- Circuit breaker state:closed(healthy),open(failing),half-open(testing)
Quick health status of the load balancer.
Endpoint: GET /health
Response (200 OK):
{
"status": "healthy",
"timestamp": "2025-10-14T10:30:00Z",
"activeProviders": 2,
"totalProviders": 2
}Response (503 Service Unavailable) - when all providers are down:
{
"status": "unhealthy",
"timestamp": "2025-10-14T10:30:00Z",
"activeProviders": 0,
"totalProviders": 2,
"reason": "No healthy providers available"
}Comprehensive health information including Redis connectivity and provider details.
Endpoint: GET /health/detailed
Response (200 OK):
{
"status": "healthy",
"timestamp": "2025-10-14T10:30:00Z",
"providers": {
"total": 2,
"healthy": 2,
"unhealthy": 0,
"details": [
{
"id": "infura",
"healthy": true,
"latencyMs": 142,
"circuitBreakerState": "closed"
},
{
"id": "alchemy",
"healthy": true,
"latencyMs": 128,
"circuitBreakerState": "closed"
}
]
},
"cache": {
"connected": true,
"hitRate": 0.73,
"keyCount": 45231
},
"uptime": 3600
}Raw Prometheus metrics for scraping.
Endpoint: GET /metrics
Response (200 OK):
# HELP rpc_lb_requests_total Total RPC requests by provider
# TYPE rpc_lb_requests_total counter
rpc_lb_requests_total{provider="infura",method="eth_blockNumber"} 1523
# HELP rpc_lb_request_duration_seconds RPC request duration
# TYPE rpc_lb_request_duration_seconds histogram
rpc_lb_request_duration_seconds_bucket{provider="infura",le="0.1"} 1200
rpc_lb_request_duration_seconds_bucket{provider="infura",le="0.5"} 1500
# HELP rpc_lb_cache_hits_total Cache hits by method
# TYPE rpc_lb_cache_hits_total counter
rpc_lb_cache_hits_total{method="eth_getBlockByNumber"} 3421
# HELP rpc_lb_provider_health Provider health status (1=healthy, 0=unhealthy)
# TYPE rpc_lb_provider_health gauge
rpc_lb_provider_health{provider="infura"} 1
Administrative endpoints for managing providers and cache. Requires authentication.
All admin endpoints require HTTP Basic Authentication.
Headers:
Authorization: Basic YWRtaW46Y2hhbmdlbWU=Or using curl:
curl -u admin:changeme http://localhost:8081/admin/providersDefault Credentials:
- Username:
admin - Password:
changeme(change viaADMIN_PASSWORDenvironment variable)
Error Response (401 Unauthorized):
{
"error": "Authentication required"
}Get detailed information about all configured providers.
Endpoint: GET /admin/providers
Authentication: Required (Basic Auth)
Response (200 OK):
{
"providers": [
{
"id": "infura",
"url": "https://mainnet.infura.io/v3/YOUR_KEY",
"healthy": true,
"weight": 85.2,
"requestCount": 1523,
"errorCount": 3,
"avgLatencyMs": 142,
"successRate": 0.998,
"lastHealthCheck": "2025-10-14T10:29:45Z",
"circuitBreakerState": "closed",
"circuitBreakerStats": {
"failures": 0,
"lastFailureTime": null,
"nextRetryTime": null
}
}
],
"summary": {
"totalProviders": 2,
"healthyProviders": 2,
"totalRequests": 3210,
"totalErrors": 4,
"avgLatencyMs": 135
}
}Get detailed information about a single provider.
Endpoint: GET /admin/providers/:id
Authentication: Required (Basic Auth)
Path Parameters:
id- Provider identifier (e.g.,infura)
Example:
curl -u admin:changeme http://localhost:8081/admin/providers/infuraResponse (200 OK):
{
"id": "infura",
"url": "https://mainnet.infura.io/v3/YOUR_KEY",
"healthy": true,
"weight": 85.2,
"requestCount": 1523,
"errorCount": 3,
"avgLatencyMs": 142,
"successRate": 0.998,
"lastHealthCheck": "2025-10-14T10:29:45Z",
"circuitBreakerState": "closed",
"circuitBreakerStats": {
"failures": 0,
"lastFailureTime": null,
"nextRetryTime": null
},
"recentRequests": [
{
"method": "eth_blockNumber",
"latencyMs": 145,
"success": true,
"timestamp": "2025-10-14T10:29:45Z"
}
]
}Error Response (404 Not Found):
{
"error": "Provider not found",
"providerId": "unknown"
}Add a new RPC provider to the pool.
Endpoint: POST /admin/providers
Authentication: Required (Basic Auth)
Headers:
Content-Type: application/jsonRequest Body:
{
"id": "quicknode",
"url": "https://ethereum.quicknode.com/YOUR_KEY",
"weight": 1,
"priority": 1
}Request Fields:
id(required) - Unique identifier for the providerurl(required) - RPC endpoint URLweight(optional) - Initial weight, default: 1priority(optional) - Provider priority, default: 1
Example:
curl -u admin:changeme -X POST http://localhost:8081/admin/providers \
-H "Content-Type: application/json" \
-d '{
"id": "quicknode",
"url": "https://ethereum.quicknode.com/YOUR_KEY",
"weight": 1
}'Response (201 Created):
{
"success": true,
"message": "Provider added successfully",
"provider": {
"id": "quicknode",
"url": "https://ethereum.quicknode.com/YOUR_KEY",
"healthy": false,
"weight": 1,
"requestCount": 0,
"errorCount": 0
}
}Error Response (400 Bad Request):
{
"error": "Provider with this ID already exists"
}Update provider configuration (weight, health status).
Endpoint: PATCH /admin/providers/:id
Authentication: Required (Basic Auth)
Path Parameters:
id- Provider identifier
Headers:
Content-Type: application/jsonRequest Body (all fields optional):
{
"weight": 2,
"healthy": false
}Example:
# Update weight
curl -u admin:changeme -X PATCH http://localhost:8081/admin/providers/infura \
-H "Content-Type: application/json" \
-d '{"weight": 2}'
# Force disable provider
curl -u admin:changeme -X PATCH http://localhost:8081/admin/providers/infura \
-H "Content-Type: application/json" \
-d '{"healthy": false}'Response (200 OK):
{
"success": true,
"message": "Provider updated successfully",
"provider": {
"id": "infura",
"weight": 2,
"healthy": false
}
}Remove a provider from the pool.
Endpoint: DELETE /admin/providers/:id
Authentication: Required (Basic Auth)
Path Parameters:
id- Provider identifier
Example:
curl -u admin:changeme -X DELETE http://localhost:8081/admin/providers/infuraResponse (200 OK):
{
"success": true,
"message": "Provider removed successfully",
"providerId": "infura"
}Error Response (404 Not Found):
{
"error": "Provider not found"
}Force-enable a provider, overriding circuit breaker state.
Endpoint: POST /admin/providers/:id/enable
Authentication: Required (Basic Auth)
Path Parameters:
id- Provider identifier
Example:
curl -u admin:changeme -X POST http://localhost:8081/admin/providers/infura/enableResponse (200 OK):
{
"success": true,
"message": "Provider enabled successfully",
"provider": {
"id": "infura",
"healthy": true,
"circuitBreakerState": "closed"
}
}Force-disable a provider, preventing it from receiving traffic.
Endpoint: POST /admin/providers/:id/disable
Authentication: Required (Basic Auth)
Path Parameters:
id- Provider identifier
Example:
curl -u admin:changeme -X POST http://localhost:8081/admin/providers/infura/disableResponse (200 OK):
{
"success": true,
"message": "Provider disabled successfully",
"provider": {
"id": "infura",
"healthy": false,
"circuitBreakerState": "open"
}
}Get detailed cache statistics.
Endpoint: GET /admin/cache/stats
Authentication: Required (Basic Auth)
Example:
curl -u admin:changeme http://localhost:8081/admin/cache/statsResponse (200 OK):
{
"connected": true,
"totalKeys": 45231,
"hitRate": 0.73,
"missRate": 0.27,
"hits": 12543,
"misses": 4621,
"memoryUsage": {
"used": "52.4 MB",
"peak": "68.2 MB"
},
"keysByMethod": {
"eth_getBlockByNumber": 32145,
"eth_getTransactionByHash": 8234,
"eth_getBlockByHash": 3456,
"eth_getTransactionReceipt": 1396
},
"ttlDistribution": {
"infinite": 30124,
"5min": 12345,
"30sec": 2762
}
}Clear cache entries by scope.
Endpoint: DELETE /admin/cache
Authentication: Required (Basic Auth)
Headers:
Content-Type: application/jsonRequest Body:
{
"scope": "all" | "provider" | "pattern",
"providerId": "infura",
"pattern": "eth_getBlock*"
}Request Fields:
scope(required) - Cache clearing scope:all- Clear entire cacheprovider- Clear cache for specific provider (requiresproviderId)pattern- Clear cache matching pattern (requirespattern)
providerId(conditional) - Provider ID whenscope=providerpattern(conditional) - Glob pattern whenscope=pattern
Examples:
# Clear entire cache
curl -u admin:changeme -X DELETE http://localhost:8081/admin/cache \
-H "Content-Type: application/json" \
-d '{"scope": "all"}'
# Clear cache for specific provider
curl -u admin:changeme -X DELETE http://localhost:8081/admin/cache \
-H "Content-Type: application/json" \
-d '{"scope": "provider", "providerId": "infura"}'
# Clear cache by pattern
curl -u admin:changeme -X DELETE http://localhost:8081/admin/cache \
-H "Content-Type: application/json" \
-d '{"scope": "pattern", "pattern": "eth_getBlock*"}'Response (200 OK):
{
"success": true,
"message": "Cache cleared successfully",
"keysDeleted": 15423,
"scope": "all"
}200 OK- Request succeeded201 Created- Resource created successfully400 Bad Request- Invalid request body or parameters401 Unauthorized- Authentication required or invalid credentials404 Not Found- Resource not found500 Internal Server Error- Server error503 Service Unavailable- All providers unavailable
Following the JSON-RPC 2.0 specification:
-32700- Parse error-32600- Invalid request-32601- Method not found-32602- Invalid params-32603- Internal error (provider failures)-32000to-32099- Server error (custom)
Currently, there is no rate limiting on the public API. For production deployments, consider:
- Adding rate limiting middleware (e.g.,
express-rate-limit) - Implementing API key-based rate limiting
- Using a reverse proxy with rate limiting (e.g., Nginx, Cloudflare)
CORS is enabled by default for all origins. To restrict origins, set the CORS_ORIGIN environment variable:
CORS_ORIGIN=https://yourdapp.com- Documentation: README.md
- Issues: GitHub Issues
- Architecture: See README.md - Architecture Diagrams