Gateway API
The Gateway provides direct node access for latency-critical MEV operations, bypassing the standard API layer for minimal overhead.
Key Features
- Direct RPC access - Minimal processing overhead
- WebSocket connections - Persistent low-latency connections
- Beacon API access - Blob data and head subscriptions
- Health monitoring - Per-endpoint status tracking
- Automatic failover - Switches to healthy nodes
Supported Chains
EthereumOptimismBaseArbitrum
Endpoints
Get Gateway Status
GET /v1/gateway/status
Returns status of all gateway endpoints.
Response
{
"status": "healthy",
"timestamp": "2026-01-15T10:30:00Z",
"endpoints": {
"ethereum": {
"rpc": {
"url": "https://gateway.axol.io/ethereum/rpc",
"status": "healthy",
"latency_ms": 25,
"block_height": 19500000
},
"ws": {
"url": "wss://gateway.axol.io/ethereum/ws",
"status": "healthy",
"connections": 150
},
"beacon": {
"url": "https://gateway.axol.io/ethereum/beacon",
"status": "healthy",
"sync_status": "synced"
}
},
"optimism": {
"rpc": {
"url": "https://gateway.axol.io/optimism/rpc",
"status": "healthy",
"latency_ms": 15
},
"ws": {
"url": "wss://gateway.axol.io/optimism/ws",
"status": "healthy"
}
},
"base": {
"rpc": {
"url": "https://gateway.axol.io/base/rpc",
"status": "healthy",
"latency_ms": 18
},
"ws": {
"url": "wss://gateway.axol.io/base/ws",
"status": "healthy"
}
}
}
}
Get Chain Status
GET /v1/gateway/chains/{chain}
Returns status for a specific chain.
curl -H "X-API-Key: YOUR_KEY" \
https://api.axol.io/api/v1/gateway/chains/ethereum
Gateway Health
GET /v1/gateway/health
Quick health check for the gateway service.
{
"status": "healthy",
"chains": {
"ethereum": "healthy",
"optimism": "healthy",
"base": "healthy"
}
}
Direct RPC Access
Endpoint URLs
Once you have gateway access, use these direct endpoints:
| Chain | RPC URL | WebSocket URL |
|---|---|---|
| ethereum | https://gateway.axol.io/ethereum/rpc | wss://gateway.axol.io/ethereum/ws |
| optimism | https://gateway.axol.io/optimism/rpc | wss://gateway.axol.io/optimism/ws |
| base | https://gateway.axol.io/base/rpc | wss://gateway.axol.io/base/ws |
Authentication
Include your API key in requests:
curl -X POST https://gateway.axol.io/ethereum/rpc \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
WebSocket Connections
Connect
import websockets
import json
async def connect_gateway():
uri = "wss://gateway.axol.io/ethereum/ws"
headers = {"X-API-Key": API_KEY}
async with websockets.connect(uri, extra_headers=headers) as ws:
# Subscribe to new blocks
await ws.send(json.dumps({
"jsonrpc": "2.0",
"method": "eth_subscribe",
"params": ["newHeads"],
"id": 1
}))
async for message in ws:
data = json.loads(message)
if "params" in data:
block = data["params"]["result"]
print(f"New block: {int(block['number'], 16)}")
Subscriptions
Standard Ethereum subscriptions are supported:
| Subscription | Description |
|---|---|
newHeads | New block headers |
newPendingTransactions | Pending transaction hashes |
logs | Event logs matching filter |
syncing | Sync status changes |
Beacon API
For Ethereum mainnet, access beacon chain data:
Endpoint
https://gateway.axol.io/ethereum/beacon
Example Requests
# Get current head
curl -H "X-API-Key: YOUR_KEY" \
https://gateway.axol.io/ethereum/beacon/eth/v1/beacon/headers/head
# Get blob sidecars
curl -H "X-API-Key: YOUR_KEY" \
https://gateway.axol.io/ethereum/beacon/eth/v1/beacon/blob_sidecars/head
# Get validator info
curl -H "X-API-Key: YOUR_KEY" \
"https://gateway.axol.io/ethereum/beacon/eth/v1/beacon/states/head/validators?id=0,1,2"
Code Examples
Python - Low Latency RPC
import aiohttp
import asyncio
import time
class GatewayClient:
def __init__(self, api_key: str, chain: str = "ethereum"):
self.api_key = api_key
self.chain = chain
self.rpc_url = f"https://gateway.axol.io/{chain}/rpc"
self.session = None
async def connect(self):
"""Initialize persistent connection."""
connector = aiohttp.TCPConnector(
limit=100,
keepalive_timeout=30,
enable_cleanup_closed=True
)
self.session = aiohttp.ClientSession(
connector=connector,
headers={"X-API-Key": self.api_key}
)
async def close(self):
if self.session:
await self.session.close()
async def call(self, method: str, params: list = None) -> dict:
"""Make RPC call."""
payload = {
"jsonrpc": "2.0",
"method": method,
"params": params or [],
"id": int(time.time() * 1000)
}
async with self.session.post(self.rpc_url, json=payload) as resp:
data = await resp.json()
if "error" in data:
raise Exception(data["error"]["message"])
return data["result"]
async def get_block_number(self) -> int:
result = await self.call("eth_blockNumber")
return int(result, 16)
async def get_gas_price(self) -> int:
result = await self.call("eth_gasPrice")
return int(result, 16)
async def send_raw_transaction(self, signed_tx: str) -> str:
return await self.call("eth_sendRawTransaction", [signed_tx])
# Usage
async def main():
client = GatewayClient(api_key=os.getenv("AXOL_API_KEY"))
await client.connect()
try:
block = await client.get_block_number()
print(f"Current block: {block}")
gas = await client.get_gas_price()
print(f"Gas price: {gas / 1e9:.2f} gwei")
finally:
await client.close()
asyncio.run(main())
TypeScript - WebSocket Subscription
import WebSocket from 'ws';
class GatewayWebSocket {
private ws: WebSocket | null = null;
private apiKey: string;
private chain: string;
private subscriptions: Map<string, (data: any) => void> = new Map();
constructor(apiKey: string, chain = 'ethereum') {
this.apiKey = apiKey;
this.chain = chain;
}
connect(): Promise<void> {
return new Promise((resolve, reject) => {
const url = `wss://gateway.axol.io/${this.chain}/ws`;
this.ws = new WebSocket(url, {
headers: { 'X-API-Key': this.apiKey }
});
this.ws.on('open', () => {
console.log('Gateway WebSocket connected');
resolve();
});
this.ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
// Handle subscription notification
if (msg.method === 'eth_subscription') {
const subId = msg.params.subscription;
const callback = this.subscriptions.get(subId);
if (callback) {
callback(msg.params.result);
}
}
});
this.ws.on('error', reject);
});
}
async subscribe(
type: 'newHeads' | 'newPendingTransactions' | 'logs',
callback: (data: any) => void,
params?: any[]
): Promise<string> {
const id = Date.now();
return new Promise((resolve, reject) => {
const handler = (data: Buffer) => {
const msg = JSON.parse(data.toString());
if (msg.id === id) {
this.ws?.off('message', handler);
if (msg.error) {
reject(new Error(msg.error.message));
} else {
const subId = msg.result;
this.subscriptions.set(subId, callback);
resolve(subId);
}
}
};
this.ws?.on('message', handler);
this.ws?.send(JSON.stringify({
jsonrpc: '2.0',
method: 'eth_subscribe',
params: params ? [type, ...params] : [type],
id
}));
});
}
async unsubscribe(subscriptionId: string): Promise<boolean> {
const id = Date.now();
return new Promise((resolve) => {
const handler = (data: Buffer) => {
const msg = JSON.parse(data.toString());
if (msg.id === id) {
this.ws?.off('message', handler);
this.subscriptions.delete(subscriptionId);
resolve(msg.result);
}
};
this.ws?.on('message', handler);
this.ws?.send(JSON.stringify({
jsonrpc: '2.0',
method: 'eth_unsubscribe',
params: [subscriptionId],
id
}));
});
}
close(): void {
this.ws?.close();
}
}
// Usage
async function main() {
const gateway = new GatewayWebSocket(process.env.AXOL_API_KEY!);
await gateway.connect();
// Subscribe to new blocks
await gateway.subscribe('newHeads', (block) => {
console.log(`New block: ${parseInt(block.number, 16)}`);
console.log(` Gas used: ${parseInt(block.gasUsed, 16)}`);
console.log(` Transactions: ${block.transactions?.length || 0}`);
});
// Subscribe to pending transactions
await gateway.subscribe('newPendingTransactions', (txHash) => {
console.log(`Pending tx: ${txHash}`);
});
console.log('Listening for blocks and transactions...');
}
main();
Python - Beacon API for Blob Data
import aiohttp
import asyncio
class BeaconClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://gateway.axol.io/ethereum/beacon"
self.session = None
async def connect(self):
self.session = aiohttp.ClientSession(
headers={"X-API-Key": self.api_key}
)
async def close(self):
if self.session:
await self.session.close()
async def get(self, path: str) -> dict:
url = f"{self.base_url}{path}"
async with self.session.get(url) as resp:
return await resp.json()
async def get_head(self) -> dict:
"""Get current head block."""
return await self.get("/eth/v1/beacon/headers/head")
async def get_blob_sidecars(self, block_id: str = "head") -> dict:
"""Get blob sidecars for a block."""
return await self.get(f"/eth/v1/beacon/blob_sidecars/{block_id}")
async def get_validators(self, indices: list[int]) -> dict:
"""Get validator information."""
ids = ",".join(map(str, indices))
return await self.get(f"/eth/v1/beacon/states/head/validators?id={ids}")
async def get_sync_status(self) -> dict:
"""Get sync committee status."""
return await self.get("/eth/v1/node/syncing")
# Usage
async def main():
client = BeaconClient(api_key=os.getenv("AXOL_API_KEY"))
await client.connect()
try:
# Get current head
head = await client.get_head()
print(f"Head slot: {head['data']['header']['message']['slot']}")
# Get blob sidecars
blobs = await client.get_blob_sidecars()
print(f"Blobs in head: {len(blobs.get('data', []))}")
# Check sync status
sync = await client.get_sync_status()
print(f"Syncing: {sync['data']['is_syncing']}")
finally:
await client.close()
asyncio.run(main())
Best Practices
1. Use Connection Pooling
Maintain persistent connections for lower latency:
# Create once, reuse
connector = aiohttp.TCPConnector(limit=100, keepalive_timeout=30)
session = aiohttp.ClientSession(connector=connector)
# Use for all requests
await session.post(url, json=payload)
2. Prefer WebSocket for Subscriptions
For real-time data, WebSocket beats polling:
# Good - WebSocket subscription
async for block in subscribe_blocks():
process(block)
# Bad - Polling
while True:
block = await get_latest_block()
if block != last_block:
process(block)
await asyncio.sleep(0.1)
3. Handle Disconnections
Implement automatic reconnection:
async def resilient_connection():
while True:
try:
async with websockets.connect(uri) as ws:
async for msg in ws:
process(msg)
except websockets.ConnectionClosed:
await asyncio.sleep(1)
4. Monitor Latency
Track your latency to detect issues:
import time
async def timed_call(method: str) -> tuple[dict, float]:
start = time.perf_counter()
result = await client.call(method)
latency = (time.perf_counter() - start) * 1000
return result, latency
result, latency_ms = await timed_call("eth_blockNumber")
print(f"Latency: {latency_ms:.1f}ms")
Rate Limits
Gateway endpoints have elevated rate limits for MEV use cases:
| Tier | RPC Requests/sec | WebSocket Connections |
|---|---|---|
| Free | 10 | 1 |
| Pro | 100 | 5 |
| Enterprise | 1000 | 50 |
See Also
- Gas Oracle - Gas prices
- Mempool Streaming - Transaction monitoring
- MEV Bundles - Bundle submission