Node Service
Multi-chain JSON-RPC access through a unified gateway format.
Overview
ZAN Node Service provides JSON-RPC access to 26 blockchain ecosystems across 44 networks. The gateway exposes a unified request format — agents call any chain using the same POST /rpc/{ecosystem}/{network} structure, and the gateway handles protocol conversion internally (e.g., REST ↔ JSON-RPC for chains like Aptos and TON).
For complete method documentation, parameter formats, and chain-specific details, see the ZAN Node Service API Reference.
Quick start
import { createX402Client } from '@zan_team/x402';
const client = await createX402Client({
gatewayUrl: 'https://x402.zan.top',
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
autoPayment: true,
preAuth: true,
});
// Simple call (no params)
const block = await client.call('eth', 'mainnet', 'eth_blockNumber');
console.log(block.result); // "0x1234567"
// Call with params
const blockData = await client.call('eth', 'mainnet', 'eth_getBlockByHash', [
'0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35',
false,
]);
console.log(blockData.result);Unified gateway format
All chains use the same request pattern regardless of their native protocol:
client.call(ecosystem, network, method, params?)The gateway internally converts between protocols as needed:
- EVM chains → native JSON-RPC passthrough
- Solana → Solana JSON-RPC passthrough
- Aptos → REST API converted to JSON-RPC format
- TON → REST API converted to JSON-RPC format
Agents don't need to know the underlying protocol — just use the unified format.
HTTP interface (reference)
POST /rpc/{ecosystem}/{network}
Authorization: Bearer <jwt>
Content-Type: application/json
{"jsonrpc": "2.0", "id": 1, "method": "eth_blockNumber", "params": []}
Response:
{"jsonrpc": "2.0", "id": 1, "result": "0x1234567"}Billing
Credits are prepurchased via x402 payment and deducted per call based on method weight.
Method weights
Credit costs are sourced from the ns-common-commercial package, with per-chain pricing definitions. Below are representative costs for Ethereum methods:
| Credits | Methods |
|---|---|
| 0 | eth_chainId, eth_syncing, net_version, net_listening |
| 10 | eth_blockNumber, eth_gasPrice, eth_maxPriorityFeePerGas, eth_feeHistory, eth_accounts |
| 15 | eth_getBalance, eth_getTransactionByHash, eth_getTransactionReceipt, eth_getBlockTransactionCountByHash, eth_getBlockTransactionCountByNumber |
| 20 | eth_getStorageAt, eth_getTransactionByBlockHashAndIndex |
| 25 | eth_getBlockByHash, eth_getBlockByNumber, eth_getCode, eth_getTransactionCount, eth_getFilterChanges |
| 40 | eth_call |
| 75 | eth_getLogs, eth_getFilterLogs |
| 80 | debug_traceTransaction, debug_traceCall, eth_blobBaseFee |
| 100 | eth_estimateGas |
| 200 | eth_sendRawTransaction |
| 250 | eth_getBlockReceipts, debug_getRawReceipts |
| 500 | debug_traceBlockByHash, debug_traceBlockByNumber, trace_block |
Note: Different chains have their own method enums with chain-specific pricing. The default cost for methods not defined in the enum is 10 credits. For the full list of methods and costs per chain, see the ZAN Node Service API Reference.
Supported chains
Layer 1
| Ecosystem | Networks |
|---|---|
eth | mainnet, sepolia, hoodi |
solana | mainnet, devnet |
bitcoin | mainnet, testnet |
tron | mainnet, nile |
ton | mainnet |
near | mainnet, testnet |
Layer 2
| Ecosystem | Networks |
|---|---|
arbitrum | one, sepolia |
optimism | mainnet, sepolia |
base | mainnet, sepolia |
zksync | mainnet |
starknet | mainnet |
mantle | mainnet |
taiko | mainnet |
Other EVM
| Ecosystem | Networks |
|---|---|
bsc | mainnet, testnet |
polygon | mainnet, amoy |
avalanche | mainnet, fuji |
fantom | mainnet |
core | mainnet |
xlayer | mainnet |
gravity_alpha | mainnet |
hyperliquid | mainnet, testnet |
monad | mainnet, testnet |
Non-EVM
| Ecosystem | Networks |
|---|---|
sui | mainnet, testnet |
aptos | mainnet, testnet |
Emerging
| Ecosystem | Networks |
|---|---|
pharos | mainnet, atlantic |
jovay | mainnet, testnet |
Blocked methods
The following methods are blocked for security reasons:
eth_accountseth_signpersonal_signeth_sendTransactioneth_signTransactiondebug_traceTransactiondebug_traceBlockByNumberdebug_traceBlockByHash
Calling a blocked method returns MethodNotAllowedError (HTTP 403).
Error handling
| Error | HTTP | Scenario | SDK behavior (autoPayment: true) |
|---|---|---|---|
InsufficientCreditsError | 402 | Credit balance too low | Auto-purchases credits, retries |
MethodNotAllowedError | 403 | Method is blocked | Throws (cannot retry) |
ProviderNotFoundError | 404 | Invalid ecosystem/network | Throws |
UpstreamError | 502/504 | Upstream node failure | Throws (credits refunded) |
NetworkError | — | Timeout / connection error | Throws |
Automatic refund
If the upstream node returns an error (5xx) after credits have been deducted, the gateway automatically refunds the credits. The UpstreamError includes a creditRefunded: true flag.
Examples
Multi-chain query
const chains = [
{ eco: 'eth', net: 'mainnet' },
{ eco: 'polygon', net: 'mainnet' },
{ eco: 'arbitrum', net: 'one' },
{ eco: 'base', net: 'mainnet' },
];
const blocks = await Promise.all(
chains.map(({ eco, net }) => client.call(eco, net, 'eth_blockNumber'))
);
blocks.forEach((b, i) => {
console.log(`${chains[i].eco}: ${parseInt(b.result, 16)}`);
});Get token balance
// ERC-20 balanceOf call
const result = await client.call('eth', 'mainnet', 'eth_call', [{
to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
data: '0x70a08231000000000000000000000000<address padded to 32 bytes>',
}, 'latest']);
console.log(`USDC balance (raw): ${result.result}`);Solana account info
const info = await client.call('solana', 'mainnet', 'getAccountInfo', [
'vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg',
{ encoding: 'jsonParsed' }
]);
console.log(info.result);Error handling pattern
import { InsufficientCreditsError, UpstreamError, MethodNotAllowedError } from '@zan_team/x402';
try {
const result = await client.call('eth', 'mainnet', 'eth_getLogs', [{
fromBlock: '0x0',
toBlock: 'latest',
address: '0x...',
}]);
} catch (err) {
if (err instanceof UpstreamError) {
console.log('Upstream failed, credits refunded — safe to retry');
} else if (err instanceof MethodNotAllowedError) {
console.log('This method is blocked');
}
}Discover available networks
const { networks } = await client.discovery.listNetworks();
networks.forEach(n => {
console.log(`${n.ecosystem}/${n.network} (provider: ${n.providerId})`);
});Next steps
- ZAN Node Service API Reference — Complete method documentation per chain
- SDK Reference —
client.call()API details - x402 Payment — How credit purchase works
- Quick Start — Get started in 3 minutes
Updated about 10 hours ago
