Skip to main content

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:

ChainRPC URLWebSocket URL
ethereumhttps://gateway.axol.io/ethereum/rpcwss://gateway.axol.io/ethereum/ws
optimismhttps://gateway.axol.io/optimism/rpcwss://gateway.axol.io/optimism/ws
basehttps://gateway.axol.io/base/rpcwss://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:

SubscriptionDescription
newHeadsNew block headers
newPendingTransactionsPending transaction hashes
logsEvent logs matching filter
syncingSync 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:

TierRPC Requests/secWebSocket Connections
Free101
Pro1005
Enterprise100050

See Also