
Quicknode
- 14 installs
- 1.2k repo stars
- Updated August 1, 2026
- bankrbot/openclaw-skills
quicknode is a Claude Code skill that gives an AI agent blockchain RPC read access (balances, prices, gas, receipts, blocks) across Base, Ethereum, Polygon, Solana, and Unichain via QuickNode API keys or x402 pay-per-req
About
quicknode is a Claude skill for reading blockchain data through QuickNode RPC endpoints across Base, Ethereum, Polygon, Solana, and Unichain. It supports both authenticated API-key endpoints and x402 wallet-based pay-per-request access with no account. It documents common agent operations such as checking balances, gas estimates, and transaction receipts, plus Marketplace add-ons like the Token, NFT, and Solana trading APIs. A developer uses it to give an agent on-chain read access across multiple networks.
- Reads on-chain data (balances, prices, gas, receipts) across Base, Ethereum, Polygon, Solana, and Unichain
- Supports API-key endpoints or x402 wallet-based pay-per-request with no account
- Documents RPC calls and Marketplace add-ons for trading agents
Quicknode by the numbers
- 14 all-time installs (skills.sh)
- Ranked #280 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
quicknode capabilities & compatibility
Free tier via API key or pay-per-request with USDC on x402 (mainnet 1M credits for $10)
- Capabilities
- litcoin miner · symbiosis
- Use cases
- api development
- Runs
- Runs locally
- Pricing
- Bring your own API key
What quicknode says it does
Quicknode provides high-performance RPC endpoints across 77+ blockchain networks including all chains Bankr supports: Base, Ethereum, Polygon, Solana, and Unichain.
x402 is ideal for autonomous agents. No signup, no API keys. Pay with USDC on Base, Polygon, or Solana.
npx skills add https://github.com/bankrbot/openclaw-skills --skill quicknodeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 14 |
|---|---|
| repo stars | ★ 1.2k |
| Last updated | August 1, 2026 |
| Repository | bankrbot/openclaw-skills ↗ |
What it does
Give an agent RPC read access to on-chain balances, prices, gas, and receipts across five chains via QuickNode API keys or x402.
Who is it for?
Trading and DeFi agents needing multi-chain on-chain reads
Skip if: Writing transactions; the skill covers RPC data reads and estimates
When should I use this skill?
An agent needs to read on-chain data like balances, token prices, transaction status, gas estimates, or block data
By the numbers
- 77+ blockchain networks supported
- 5 Bankr-supported chains documented
- mainnet pricing 1,000,000 credits for $10 USDC
Files
Quicknode: Blockchain Data Access for Agents
Quicknode provides high-performance RPC endpoints across 77+ blockchain networks including all chains Bankr supports: Base, Ethereum, Polygon, Solana, and Unichain.
Two ways to access:
- API key: Create a Quicknode account, get an endpoint URL with auth baked in. Full access to all products and settings.
- x402 (no account needed): Any wallet with USDC can authenticate and pay per request. Install
@quicknode/x402and start querying immediately.
x402 Access (Recommended for Agents)
x402 is ideal for autonomous agents. No signup, no API keys. Pay with USDC on Base, Polygon, or Solana.
import { createQuicknodeX402Client } from "@quicknode/x402";
const client = await createQuicknodeX402Client({
baseUrl: 'https://x402.quicknode.com',
network: "eip155:84532", // pay on Base Sepolia (testnet)
evmPrivateKey: process.env.PRIVATE_KEY,
preAuth: true, // pre-authenticates via SIWX for faster payment flow
});
// Pay on Base, query any chain
const res = await client.fetch("https://x402.quicknode.com/ethereum-mainnet", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", method: "eth_blockNumber", params: [], id: 1 }),
});Install: npm install @quicknode/x402
Credit pricing:
- Testnet: 100 credits for $0.01 USDC
- Mainnet: 1,000,000 credits for $10 USDC
- 1 credit per successful JSON-RPC response
Full x402 docs: https://x402.quicknode.com/llms.txt
API Key Access
Quicknode endpoints include authentication in the URL:
https://{ENDPOINT_NAME}.{NETWORK}.quiknode.pro/{API_KEY}/import { createPublicClient, http } from "viem";
import { base } from "viem/chains";
const client = createPublicClient({
chain: base,
transport: http(process.env.QUICKNODE_RPC_URL),
});
const block = await client.getBlockNumber();Common Agent Operations
Check Native Balance (EVM)
const balance = await client.getBalance({ address: "0x..." });Or raw RPC:
{ "jsonrpc": "2.0", "method": "eth_getBalance", "params": ["0x...", "latest"], "id": 1 }Check ERC-20 Token Balance (EVM)
Use eth_call with the ERC-20 balanceOf(address) selector (0x70a08231):
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0xTOKEN_CONTRACT",
"data": "0x70a08231000000000000000000000000WALLET_ADDRESS_NO_0x"
}, "latest"],
"id": 1
}Get Gas Estimate (EVM)
{ "jsonrpc": "2.0", "method": "eth_gasPrice", "params": [], "id": 1 }Check Transaction Status (EVM)
{ "jsonrpc": "2.0", "method": "eth_getTransactionReceipt", "params": ["0xTX_HASH"], "id": 1 }Solana Balance
{ "jsonrpc": "2.0", "method": "getBalance", "params": ["WALLET_PUBKEY"], "id": 1 }Solana Token Accounts
{
"jsonrpc": "2.0",
"method": "getTokenAccountsByOwner",
"params": [
"WALLET_PUBKEY",
{ "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
{ "encoding": "jsonParsed" }
],
"id": 1
}Quicknode Marketplace Add-ons
Quicknode endpoints can be enhanced with Marketplace add-ons. Relevant ones for trading agents:
- Token API:
qn_getWalletTokenBalancereturns all ERC-20 balances for a wallet in one call. No need to query each token contract individually. - NFT API:
qn_fetchNFTsreturns NFTs owned by an address with metadata. - Solana Priority Fee API:
qn_estimatePriorityFeesreturns recommended priority fees based on recent network activity. Useful for ensuring transactions land quickly. - Solana DAS API: Query compressed NFTs, fungible tokens, and digital assets via methods like
getAssetsByOwnerandsearchAssets. - Metis - Solana Trading API: Jupiter-powered token swaps on Solana. Get quotes and execute swaps via
quoteGetandswapPostendpoints. Docs: https://www.quicknode.com/docs/solana/metis-overview
See all add-ons: https://marketplace.quicknode.com/
These add-ons are available on API key endpoints. Enable them in the Quicknode dashboard.
Supported Networks
All Bankr-supported chains are available on Quicknode:
| Chain | x402 Network Slug | API Key Docs |
|---|---|---|
| Base | base-mainnet | https://www.quicknode.com/docs/base |
| Ethereum | ethereum-mainnet | https://www.quicknode.com/docs/ethereum |
| Polygon | polygon-mainnet | https://www.quicknode.com/docs/polygon |
| Solana | solana-mainnet | https://www.quicknode.com/docs/solana |
| Unichain | unichain-mainnet | https://www.quicknode.com/docs/unichain |
x402 base URL: https://x402.quicknode.com/{network-slug}
See full list of supported chains: https://www.quicknode.com/chains
Error Handling
- 429 Too Many Requests: Back off and retry. Use exponential backoff.
- 402 Payment Required (x402): Credits depleted.
@quicknode/x402handles this automatically by triggering a new USDC payment. - JSON-RPC errors (e.g.,
-32000): Method-specific errors. Check params and retry.
Resources
- AI & Agents docs: https://www.quicknode.com/docs/build-with-ai
- Full RPC documentation (all chains): https://www.quicknode.com/docs/llms.txt
- x402 technical details: https://x402.quicknode.com/llms.txt
- Code examples (x402): https://github.com/quiknode-labs/qn-x402-examples
- Marketplace add-ons: https://marketplace.quicknode.com
- Full Quicknode skill with extended references: https://github.com/quiknode-labs/blockchain-skills/tree/main/skills/quicknode-skill
HyperCore & Hyperliquid Reference
Quicknode provides infrastructure for the Hyperliquid L1 chain through HyperCore, delivering gRPC, JSON-RPC, WebSocket, and Info API access to exchange and trading data, plus HyperEVM RPC for smart contract execution.
Overview
| Property | Value |
|---|---|
| Chain | Hyperliquid L1 |
| Consensus | HyperBFT (based on HotStuff) |
| Native Token | HYPE |
| Mainnet Chain ID | 999 |
| Testnet Chain ID | 998 |
| Block Rate | ~12 blocks/sec |
| Status | Public Beta |
| gRPC Compression | zstd (~70% bandwidth reduction) |
| Architecture | HyperCore (exchange/trading) + HyperEVM (smart contracts) |
Network Configuration
| Network | Endpoint Pattern | Chain ID |
|---|---|---|
| Mainnet | https://[name].hype-mainnet.quiknode.pro/[token]/ | 999 (0x3E7) |
| Testnet | https://[name].hype-testnet.quiknode.pro/[token]/ | 998 |
Testnet is pruned to the last 250 blocks.
HyperCore Access Methods
| Method | Path / Port | Protocol | Description |
|---|---|---|---|
| Info | /info | HTTP POST | 50+ specialized methods for market data, positions, orders |
| JSON-RPC | /hypercore | HTTP POST | Block queries: hl_getLatestBlocks, hl_getBlock, hl_getBatchBlocks |
| WebSocket | /hypercore/ws | WebSocket | Real-time subscriptions: hl_subscribe, hl_unsubscribe |
| gRPC | Port 10000 | gRPC (HTTP/2) | Lowest latency streaming: Ping, StreamBlocks, StreamData |
Authentication
URL Token (default)
https://your-endpoint.hype-mainnet.quiknode.pro/your-auth-token/Header-Based
curl -H "x-token: your-auth-token" \
https://your-endpoint.hype-mainnet.quiknode.pro/evmgRPC Authentication
const grpc = require("@grpc/grpc-js");
const metadata = new grpc.Metadata();
metadata.add("x-token", "your-auth-token");
// Pass metadata to all gRPC callsEndpoint for gRPC: your-endpoint.hype-mainnet.quiknode.pro:10000 (TLS required).
Info Endpoint
The Info API provides 50+ methods for querying Hyperliquid exchange data. All requests are POST to /info with a type field.
Note: Some Info methods (e.g.,allMids,l2Book,meta) are also available via Hyperliquid's public endpoints without a Quicknode subscription. Check https://www.quicknode.com/docs/hyperliquid/llms.txt for details on which methods require a Quicknode endpoint vs. public access.
Base URL
https://[endpoint].hype-mainnet.quiknode.pro/[token]/infoQuick Example
const response = await fetch(
`${process.env.QUICKNODE_RPC_URL}info`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ type: "allMids" }),
}
);
const midPrices = await response.json();
// { "BTC": "92385.0", "ETH": "3167.4", ... }Key Methods
Method (type) | Parameters | Description |
|---|---|---|
allMids | — | Real-time mid-market prices for all pairs |
l2Book | coin | Level 2 order book (up to 20 levels per side) |
recentTrades | coin | Recent executed trades |
candleSnapshot | coin, interval, startTime, endTime | OHLCV candlestick data |
meta | — | Exchange metadata: trading pairs, leverage limits |
metaAndAssetCtxs | — | Market data with funding, OI, oracle prices |
spotMeta | — | Spot market metadata |
spotMetaAndAssetCtxs | — | Spot metadata with prices |
clearinghouseState | user | Account positions, margin, P&L |
spotClearinghouseState | user | Spot token balances |
openOrders | user | All open orders for a user |
frontendOpenOrders | user | Open orders (frontend format) |
historicalOrders | user | Up to 2,000 recent historical orders |
orderStatus | user, oid | Status of a specific order |
userFills | user | Up to 2,000 recent trade executions |
userFillsByTime | user, startTime | Fills within a time range |
fundingHistory | coin, startTime | Historical funding rates |
predictedFundings | — | Forecasted funding rates |
activeAssetData | user, coin | Active trading data for user/asset |
portfolio | user | Account value and P&L history |
vaultDetails | vaultAddress | Vault analytics |
exchangeStatus | — | Exchange status and maintenance info |
JSON-RPC Methods
POST requests to /hypercore.
hl_getLatestBlocks
const response = await fetch(
`${process.env.QUICKNODE_RPC_URL}hypercore`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
method: "hl_getLatestBlocks",
params: { stream: "trades", count: 10 },
id: 1,
}),
}
);
const { result } = await response.json();
// result.blocks: [{ local_time, block_time, block_number, events }]hl_getBlock
const response = await fetch(
`${process.env.QUICKNODE_RPC_URL}hypercore`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
method: "hl_getBlock",
params: ["trades", 817824084],
id: 1,
}),
}
);hl_getBatchBlocks
const response = await fetch(
`${process.env.QUICKNODE_RPC_URL}hypercore`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
method: "hl_getBatchBlocks",
params: { stream: "trades", from: 817824078, to: 817824090 },
id: 1,
}),
}
);hl_getLatestBlockNumber
const response = await fetch(
`${process.env.QUICKNODE_RPC_URL}hypercore`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
method: "hl_getLatestBlockNumber",
params: ["events"],
id: 1,
}),
}
);WebSocket
Connect to /hypercore/ws for real-time subscriptions.
Subscribe
import WebSocket from "ws";
const ws = new WebSocket(
`${process.env.QUICKNODE_WSS_URL}hypercore/ws`
);
ws.on("open", () => {
// Subscribe to trades
ws.send(
JSON.stringify({
jsonrpc: "2.0",
method: "hl_subscribe",
params: { streamType: "trades" },
id: 1,
})
);
});
ws.on("message", (data) => {
const message = JSON.parse(data.toString());
if (message.params) {
console.log("Trade event:", message.params);
}
});
// Unsubscribe
ws.send(
JSON.stringify({
jsonrpc: "2.0",
method: "hl_unsubscribe",
params: { streamType: "trades" },
id: 2,
})
);gRPC Streaming
Port 10000 provides the lowest-latency access to HyperCore data via three RPC methods.
Connection Setup
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000";
const TOKEN = "your-auth-token";
const packageDefinition = protoLoader.loadSync("streaming.proto", {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const proto = grpc.loadPackageDefinition(packageDefinition);
const channelCredentials = grpc.credentials.createSsl();
const client = new proto.streaming.Streaming(ENDPOINT, channelCredentials, {
"grpc.max_receive_message_length": 100 * 1024 * 1024, // 100MB
});
const metadata = new grpc.Metadata();
metadata.add("x-token", TOKEN);gRPC Methods
| Method | Type | Description |
|---|---|---|
Ping | Unary | Connection health check |
StreamBlocks | Server streaming | Stream blocks from a timestamp |
StreamData | Bidirectional streaming | Subscribe to filtered data streams |
Ping
client.Ping({ count: 1 }, metadata, (error, response) => {
if (error) console.error("Ping failed:", error);
else console.log("Ping response:", response);
});StreamData (Bidirectional)
const stream = client.StreamData(metadata);
// Subscribe to trades for specific coins
stream.write({
subscribe: {
stream_type: "TRADES",
coins: ["BTC", "ETH"],
},
});
// Send keepalive pings every 30 seconds
const pingInterval = setInterval(() => {
stream.write({ ping: { timestamp: Date.now() } });
}, 30000);
stream.on("data", (response) => {
if (response.data) {
const block = JSON.parse(response.data.data);
console.log("Block:", response.data.block_number, block);
}
if (response.pong) {
console.log("Pong:", response.pong.timestamp);
}
});
stream.on("error", (error) => {
console.error("Stream error:", error);
clearInterval(pingInterval);
});
stream.on("end", () => {
clearInterval(pingInterval);
});gRPC Stream Types
| Stream Type | Volume | Available Via |
|---|---|---|
| TRADES | High | gRPC, JSON-RPC, WebSocket |
| ORDERS | Very High | gRPC, JSON-RPC, WebSocket |
| BOOK_UPDATES | Very High | gRPC, JSON-RPC, WebSocket |
| TWAP | Low | gRPC, JSON-RPC, WebSocket |
| EVENTS | High | gRPC, JSON-RPC, WebSocket |
| BLOCKS | Extreme | gRPC only |
| WRITER_ACTIONS | Low | gRPC, JSON-RPC, WebSocket |
Stream Data Details
- TRADES: Execution data — coin, price, size, side, fees, liquidation info
- ORDERS: Order lifecycle — 18+ status types (open, filled, canceled, rejected variants)
- BOOK_UPDATES: Level-2 order book diffs — individual order adds/removes
- TWAP: Time-weighted average price order updates — activated, finished, terminated
- EVENTS: Ledger updates, funding payments, deposits, withdrawals, delegations
- BLOCKS: Raw HyperCore blocks with all 34 action types (gRPC only)
- WRITER_ACTIONS: System-level spot token transfers (HyperCore to HyperEVM)
gRPC Filtering
Filter streams by coin, user, side, and other fields depending on stream type.
Filter Fields by Stream
| Stream | Available Filters |
|---|---|
| TRADES | coin, user, side, liquidation, builder |
| ORDERS | coin, user, status, builder |
| BOOK_UPDATES | coin, side |
| TWAP | coin, user, status |
| EVENTS | user, type |
| WRITER_ACTIONS | user, action.type, action.token |
Filter Logic
- AND across fields — When multiple filter fields are specified (e.g.,
coinandside), all conditions must match (AND logic). - OR within values — When a field has multiple values (e.g.,
coin: { values: ["BTC", "ETH"] }), any value can match (OR logic). - *Special value `""`** — Matches any event where the field exists (non-null).
- Special value `"null"` — Matches events where the field is explicitly null.
- Recursive matching — Filters match recursively into nested JSON structures, so top-level field filters also apply to nested objects.
Filter Limits
| Limit | Maximum |
|---|---|
Values per user / address filter | 100 |
Values per coin filter | 50 |
Values per type / status filter | 20 |
| Total filter values across all fields | 500 |
| Named filters per stream | 10 |
Filtering Examples
const stream = client.StreamData(metadata);
// Subscribe to BTC and ETH buy trades only
stream.write({
subscribe: {
stream_type: "TRADES",
filters: {
coin: { values: ["BTC", "ETH"] },
side: { values: ["B"] },
},
},
});
// Subscribe to order status changes for a specific user
stream.write({
subscribe: {
stream_type: "ORDERS",
filters: {
user: { values: ["0x2ba553d9f990a3b66b03b2dc0d030dfc1c061036"] },
status: { values: ["filled", "canceled"] },
},
},
});
// Subscribe to all events where the user field exists
stream.write({
subscribe: {
stream_type: "EVENTS",
filters: {
user: { values: ["*"] },
},
},
});
// Subscribe to liquidation trades only
stream.write({
subscribe: {
stream_type: "TRADES",
filters: {
liquidation: { values: ["*"] },
},
},
});HyperEVM
HyperEVM provides EVM-compatible smart contract execution on Hyperliquid. Two RPC paths are available:
| Path | Protocol | Archive | Debug/Trace | Use Case |
|---|---|---|---|---|
/evm | HTTP | Partial | No | Standard blockchain operations |
/nanoreth | HTTP + WebSocket | Extended | Yes (debug_*, trace_*) | Advanced debugging, tracing, subscriptions |
Standard EVM Example (/evm)
import { JsonRpcProvider } from "ethers";
const provider = new JsonRpcProvider(
`${process.env.QUICKNODE_RPC_URL}evm`
);
const blockNumber = await provider.getBlockNumber();
const balance = await provider.getBalance("0x...");Debug/Trace Example (/nanoreth)
import { JsonRpcProvider } from "ethers";
const provider = new JsonRpcProvider(
`${process.env.QUICKNODE_RPC_URL}nanoreth`
);
// Standard methods work on nanoreth too
const blockNumber = await provider.getBlockNumber();
// Debug and trace methods only available on /nanoreth
const trace = await provider.send("debug_traceTransaction", [
"0xTransactionHash...",
{ tracer: "callTracer" },
]);WebSocket Subscriptions (/nanoreth)
import { WebSocketProvider } from "ethers";
const wsProvider = new WebSocketProvider(
`${process.env.QUICKNODE_WSS_URL}nanoreth`
);
wsProvider.on("block", (blockNumber) => {
console.log("New block:", blockNumber);
});Hyperliquid-Specific EVM Methods
| Method | Description |
|---|---|
eth_getSystemTxsByBlockNumber | Internal system transactions (HyperCore-to-HyperEVM) |
eth_getSystemTxsByBlockHash | System transactions by block hash |
eth_usingBigBlocks | Check if address uses big blocks |
eth_bigBlockGasPrice | Gas price for big blocks |
Best Practices
1. Use gRPC for lowest latency — Port 10000 gRPC streaming provides sub-millisecond data delivery, ideal for trading applications. 2. Enable zstd compression — Reduces bandwidth by ~70%, critical for high-volume streams like ORDERS and BOOK_UPDATES. 3. Use `/nanoreth` for debugging — Extended archive and trace/debug methods are only available on /nanoreth, not /evm. 4. Handle ~12 blocks/sec throughput — Hyperliquid produces blocks rapidly. Ensure your consumer can process events at this rate. 5. Send gRPC keepalive pings — Send pings every 30 seconds to maintain the connection. 6. Note public beta status — HyperCore on Quicknode is in public beta. APIs and behavior may change.
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| gRPC connection refused on port 10000 | Wrong endpoint or port | Use endpoint.hype-mainnet.quiknode.pro:10000 with TLS |
| Auth failed on gRPC | Missing or wrong x-token metadata | Add metadata.add('x-token', TOKEN) to all gRPC calls |
No data from /info | Wrong path or missing type field | POST to /info with {"type": "methodName"} |
| WebSocket disconnects | No ping/pong or server maintenance | Implement reconnection logic with backoff |
/evm missing debug methods | Debug methods not available on /evm | Switch to /nanoreth for debug_* and trace_* methods |
| Testnet data missing | Testnet pruned to last 250 blocks | Use mainnet for historical data; testnet is for testing only |
| High bandwidth usage | Unfiltered high-volume streams | Apply coin/user/side filters and enable zstd compression |
Documentation
- Hyperliquid Overview: https://www.quicknode.com/docs/hyperliquid
- Hyperliquid Overview (llms.txt): : https://www.quicknode.com/docs/hyperliquid/llms.txt
- Hyperliquid gRPC API: https://www.quicknode.com/docs/hyperliquid/grpc-api
- HyperCore Filtering: https://www.quicknode.com/docs/hyperliquid/filtering
- Hyperliquid llms.txt: https://www.quicknode.com/docs/hyperliquid/llms.txt
- HyperCore Info Methods: https://www.quicknode.com/docs/hyperliquid (Info endpoint section)
- HyperEVM: https://www.quicknode.com/docs/hyperliquid (HyperEVM section)
- Guides: https://www.quicknode.com/guides/tags/hyperliquid
Quicknode Marketplace Add-ons Reference
Quicknode Marketplace provides enhanced blockchain APIs as add-ons to standard RPC endpoints. Enable add-ons in the Quicknode dashboard to access these methods.
Ethereum Token APIs
qn_getWalletTokenBalance
Get all ERC-20 token balances for an address.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'qn_getWalletTokenBalance',
params: [{
wallet: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
contracts: [] // Empty array for all tokens
}]
})
});
const { result } = await response.json();
// result.assets: Array of token balancesResponse:
{
"result": {
"owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"assets": [
{
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"balance": "1000000000",
"balanceUSD": "1000.00"
}
]
}
}qn_getTokenMetadataByContractAddress
Get token metadata for a specific contract.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'qn_getTokenMetadataByContractAddress',
params: [{
contract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
}]
})
});Response:
{
"result": {
"name": "USD Coin",
"symbol": "USDC",
"decimals": "6",
"contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
}qn_getTokenMetadataBySymbol
Get token metadata by symbol.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'qn_getTokenMetadataBySymbol',
params: [{
symbol: 'USDC'
}]
})
});Ethereum NFT APIs
qn_fetchNFTs
Fetch NFTs owned by an address.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'qn_fetchNFTs',
params: [{
wallet: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
page: 1,
perPage: 10,
contracts: [] // Optional: filter by contracts
}]
})
});
const { result } = await response.json();
// result.assets: Array of NFTs
// result.totalItems: Total count
// result.pageNumber: Current pageResponse:
{
"result": {
"owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"assets": [
{
"collectionName": "Bored Ape Yacht Club",
"collectionAddress": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
"collectionTokenId": "1234",
"name": "Bored Ape #1234",
"description": "A bored ape",
"imageUrl": "ipfs://...",
"traits": [
{ "trait_type": "Background", "value": "Blue" }
]
}
],
"totalItems": 42,
"pageNumber": 1
}
}qn_fetchNFTCollectionDetails
Get collection-level details.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'qn_fetchNFTCollectionDetails',
params: [{
contracts: ['0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D']
}]
})
});Response:
{
"result": [
{
"address": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
"name": "Bored Ape Yacht Club",
"erc": "erc721",
"totalSupply": "10000"
}
]
}qn_fetchNFTsByCollection
Fetch NFTs from a specific collection.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'qn_fetchNFTsByCollection',
params: [{
collection: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
tokens: ['1', '2', '3'], // Optional: specific tokens
page: 1,
perPage: 10
}]
})
});qn_verifyNFTsOwner
Verify NFT ownership.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'qn_verifyNFTsOwner',
params: [{
wallet: '0xWalletAddress...',
contracts: [
{
address: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
tokenIds: ['1234']
}
]
}]
})
});Solana Add-ons
Priority Fee API
Get recommended priority fees for Solana transactions.
import { createSolanaRpc } from '@solana/kit';
const rpc = createSolanaRpc(process.env.QUICKNODE_RPC_URL!);
const response = await rpc.request('qn_estimatePriorityFees', {
last_n_blocks: 100,
account: 'YourAccountPubkey...'
}).send();
// Response includes recommended fees by percentile
// per_compute_unit.low, medium, high, extremeResponse:
{
"result": {
"per_compute_unit": {
"low": 100,
"medium": 1000,
"high": 10000,
"extreme": 100000
},
"per_transaction": {
"low": 1000,
"medium": 10000,
"high": 100000,
"extreme": 1000000
}
}
}DAS API (Digital Asset Standard)
Comprehensive API for querying Solana digital assets — standard NFTs, compressed NFTs, fungible tokens, MPL Core Assets, and Token 2022 Assets. Requires the Metaplex DAS API add-on enabled on your endpoint.
Docs: https://www.quicknode.com/docs/solana/solana-das-api
// Get assets by owner
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetsByOwner',
params: { ownerAddress: 'WalletPubkey...', limit: 10 }
})
});
// Get single asset details
const asset = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAsset',
params: { id: 'AssetMintAddress...' }
})
});
// Search assets with filters
const search = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'searchAssets',
params: { ownerAddress: 'WalletPubkey...', compressed: true, limit: 10 }
})
});Available methods: getAsset, getAssets, getAssetProof, getAssetProofs, getAssetsByAuthority, getAssetsByCreator, getAssetsByGroup, getAssetsByOwner, getAssetSignatures, getTokenAccounts, getNftEditions, searchAssets
See solana-das-api-reference.md for complete DAS API documentation with all methods, parameters, and examples.
Metis Jupiter API
Access Jupiter DEX aggregator for swaps via REST endpoints on your QuickNode Solana endpoint.
Endpoint: SetQUICKNODE_METIS_URLto your QuickNode Metis endpoint (e.g.,https://jupiter-swap-api.quiknode.pro/YOUR_TOKEN). Enable the Metis - Jupiter V6 Swap API add-on in your QuickNode dashboard. Do not use the public Jupiter API for production — it has lower rate limits and no SLA.
Docs: https://www.quicknode.com/docs/solana/metis-overview
// Get swap quote (GET request)
const quoteUrl = new URL(`${process.env.QUICKNODE_METIS_URL}/quote`);
quoteUrl.searchParams.set('inputMint', 'So11111111111111111111111111111111111111112'); // SOL
quoteUrl.searchParams.set('outputMint', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // USDC
quoteUrl.searchParams.set('amount', '1000000000'); // 1 SOL in lamports
quoteUrl.searchParams.set('slippageBps', '50'); // 0.5% slippage
const quoteResponse = await fetch(quoteUrl.toString());
const quote = await quoteResponse.json();
// Execute swap (POST request)
const swapResponse = await fetch(`${process.env.QUICKNODE_METIS_URL}/swap`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userPublicKey: 'YourPubkey...',
quoteResponse: quote
})
});
const { swapTransaction, lastValidBlockHeight } = await swapResponse.json();
// swapTransaction is a serialized transaction ready for signing and sendingUsing the Jupiter SDK:
import { createJupiterApiClient } from '@jup-ag/api';
const jupiterApi = createJupiterApiClient({
basePath: `${process.env.QUICKNODE_METIS_URL}`
});
const quote = await jupiterApi.quoteGet({
inputMint: 'So11111111111111111111111111111111111111112',
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
amount: 1000000000,
slippageBps: 50
});
const swapResult = await jupiterApi.swapPost({
swapRequest: {
quoteResponse: quote,
userPublicKey: 'YourPubkey...'
}
});Yellowstone gRPC
High-performance streaming for Solana data.
// Configure in endpoint settings
// Use gRPC client to connect
const client = new YellowstoneClient({
endpoint: 'YOUR_GRPC_ENDPOINT',
token: process.env.QUICKNODE_API_KEY!
});
// Subscribe to account updates
const stream = client.subscribe({
accounts: {
accountIds: ['AccountPubkey...']
}
});
stream.on('data', (update) => {
console.log('Account updated:', update);
});For full Yellowstone gRPC documentation including all filter types, subscription examples, and multi-language setup, see yellowstone-grpc-reference.md.
Jito Bundles
MEV protection and bundle submission.
// Submit bundle
const bundleResult = await rpc.request('sendBundle', {
transactions: [
'Base64EncodedTx1...',
'Base64EncodedTx2...'
]
}).send();
// Get bundle status
const status = await rpc.request('getBundleStatuses', {
bundleIds: [bundleResult.bundleId]
}).send();EVM Trace & Debug APIs
trace_call
Trace a call without executing.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'trace_call',
params: [
{
to: '0xContractAddress...',
data: '0xFunctionSelector...'
},
['trace'],
'latest'
]
})
});trace_transaction
Get execution trace for a transaction.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'trace_transaction',
params: ['0xTransactionHash...']
})
});debug_traceTransaction
Detailed transaction debugging.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'debug_traceTransaction',
params: [
'0xTransactionHash...',
{ tracer: 'callTracer' }
]
})
});Archive Data
Access historical blockchain state.
// Get balance at specific block
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'eth_getBalance',
params: [
'0xAddress...',
'0xF4240' // Block 1,000,000
]
})
});
// Call contract at historical block
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
method: 'eth_call',
params: [
{
to: '0xContract...',
data: '0xFunctionSelector...'
},
'0xF4240' // Block 1,000,000
]
})
});Using with Quicknode SDK
import { Core } from '@quicknode/sdk';
const core = new Core({
endpointUrl: process.env.QUICKNODE_RPC_URL!,
});
// Token API
const tokenBalances = await core.client.qn_getWalletTokenBalance({
wallet: '0x...',
contracts: []
});
// NFT API
const nfts = await core.client.qn_fetchNFTs({
wallet: '0x...',
page: 1,
perPage: 10
});
// Collection details
const collection = await core.client.qn_fetchNFTCollectionDetails({
contracts: ['0x...']
});Add-on Availability by Chain
| Add-on | Ethereum | Polygon | Arbitrum | Base | Solana |
|---|---|---|---|---|---|
| Token API | Yes | - | - | - | - |
| NFT API | Yes | - | - | - | DAS |
| Trace API | Yes | Yes | Yes | Yes | - |
| Debug API | Yes | Yes | Yes | Yes | - |
| Archive | Yes | Yes | Yes | Yes | - |
| Priority Fee | - | - | - | - | Yes |
| Jupiter/Metis | - | - | - | - | Yes |
| Yellowstone | - | - | - | - | Yes |
| Jito | - | - | - | - | Yes |
Rate Limits
Add-on methods consume credits based on complexity:
| Method Type | Credits |
|---|---|
| Token balance | 50 |
| NFT fetch | 100 |
| Collection details | 50 |
| Trace call | 200 |
| Debug trace | 500 |
| Archive query | 100 |
Documentation
- Marketplace: https://marketplace.quicknode.com/
- Token API: https://www.quicknode.com/docs/ethereum/qn_getWalletTokenBalance
- NFT API: https://www.quicknode.com/docs/ethereum/qn_fetchNFTs
- Solana Add-ons: https://www.quicknode.com/docs/solana
- Metis Jupiter API: https://www.quicknode.com/docs/solana/metis-overview
- Trace API: https://www.quicknode.com/docs/ethereum/trace_call
- DAS API: https://www.quicknode.com/docs/solana/solana-das-api
- Guides: https://www.quicknode.com/guides/tags/marketplace
RPC Endpoints Reference
Quicknode provides low-latency JSON-RPC, WebSocket, and REST endpoints for 80+ blockchain networks with built-in authentication, global load balancing, and per-method documentation.
Overview
| Property | Value |
|---|---|
| Protocol | JSON-RPC 2.0 (HTTP + WebSocket), REST (Beacon Chain) |
| Chains | 80+ networks (EVM, Solana, Bitcoin, and more) |
| Authentication | Token in URL path, optional JWT or IP allowlisting |
| EVM Libraries | ethers.js, viem, web3.js |
| Solana Libraries | @solana/kit, @solana/web3.js |
| Bitcoin | Raw JSON-RPC via fetch |
| Endpoint Format | https://{name}.{network}.quiknode.pro/{token}/ |
| WebSocket Format | wss://{name}.{network}.quiknode.pro/{token}/ |
| Per-Method Docs | https://www.quicknode.com/docs/{chain}/{method} |
Connection Setup
EVM Chains
// ethers.js — HTTP
import { JsonRpcProvider } from 'ethers';
const provider = new JsonRpcProvider(process.env.QUICKNODE_RPC_URL!);
// ethers.js — WebSocket
import { WebSocketProvider } from 'ethers';
const wsProvider = new WebSocketProvider(process.env.QUICKNODE_WSS_URL!);
// viem — HTTP
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
const client = createPublicClient({
chain: mainnet,
transport: http(process.env.QUICKNODE_RPC_URL!),
});
// viem — WebSocket
import { createPublicClient, webSocket } from 'viem';
import { mainnet } from 'viem/chains';
const wsClient = createPublicClient({
chain: mainnet,
transport: webSocket(process.env.QUICKNODE_WSS_URL!),
});Solana
// @solana/kit — HTTP
import { createSolanaRpc } from '@solana/kit';
const rpc = createSolanaRpc(process.env.QUICKNODE_RPC_URL!);
// @solana/kit — WebSocket
import { createSolanaRpcSubscriptions } from '@solana/kit';
const rpcSubscriptions = createSolanaRpcSubscriptions(process.env.QUICKNODE_WSS_URL!);Bitcoin
// Raw JSON-RPC helper
async function btcRpc(method: string, params: unknown[] = []) {
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
});
const { result, error } = await response.json();
if (error) throw new Error(`${error.code}: ${error.message}`);
return result;
}EVM RPC Methods
Core Methods
| Category | Methods |
|---|---|
| Account | eth_getBalance, eth_getCode, eth_getStorageAt, eth_getAccount, eth_getTransactionCount, eth_getProof |
| Block | eth_blockNumber, eth_getBlockByHash, eth_getBlockByNumber, eth_getBlockReceipts, eth_getBlockTransactionCountByHash, eth_getBlockTransactionCountByNumber |
| Transaction | eth_getTransactionByHash, eth_getTransactionByBlockHashAndIndex, eth_getTransactionByBlockNumberAndIndex, eth_getTransactionReceipt, eth_sendRawTransaction, eth_getRawTransactionByHash |
| Call & Simulate | eth_call, eth_estimateGas, eth_simulateV1, eth_callMany |
| Logs & Filters | eth_getLogs, eth_newFilter, eth_newBlockFilter, eth_newPendingTransactionFilter, eth_getFilterChanges, eth_getFilterLogs, eth_uninstallFilter |
| Gas & Fees | eth_gasPrice, eth_maxPriorityFeePerGas, eth_feeHistory, eth_blobBaseFee |
| Network | eth_chainId, eth_syncing, net_version, net_listening, net_peerCount, web3_clientVersion, web3_sha3 |
| Subscription | eth_subscribe, eth_unsubscribe |
Code Examples
Get balance:
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'eth_getBalance',
params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'latest'],
}),
});
const { result } = await response.json();
// result: "0x..." (balance in wei, hex-encoded)Send raw transaction:
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'eth_sendRawTransaction',
params: ['0xSignedTransactionData...'],
}),
});
const { result } = await response.json();
// result: "0x..." (transaction hash)Get logs (filter by contract events):
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'eth_getLogs',
params: [{
fromBlock: '0x118C5E0',
toBlock: '0x118C5FF',
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // Transfer
],
}],
}),
});
const { result } = await response.json();
// result: Array of log objects { address, topics, data, blockNumber, transactionHash, ... }Call a contract (read-only):
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'eth_call',
params: [{
to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
data: '0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045', // balanceOf(address)
}, 'latest'],
}),
});
const { result } = await response.json();
// result: ABI-encoded return valueDebug, Trace & Extended Namespaces
| Namespace | Methods |
|---|---|
| debug | debug_traceTransaction, debug_traceCall, debug_traceBlock, debug_traceBlockByHash, debug_traceBlockByNumber, debug_getBadBlocks, debug_storageRangeAt, debug_getTrieFlushInterval |
| trace (Erigon) | trace_block, trace_call, trace_callMany, trace_filter, trace_rawTransaction, trace_replayBlockTransactions, trace_replayTransaction, trace_transaction |
| erigon | erigon_blockNumber, erigon_forks, erigon_getBlockByTimestamp, erigon_getBlockReceiptsByBlockHash, erigon_getHeaderByHash, erigon_getHeaderByNumber, erigon_getLatestLogs, erigon_getLogsByHash |
| txpool (Geth) | txpool_content, txpool_contentFrom, txpool_inspect, txpool_status |
Quicknode Custom Methods (qn_*)
| Method | Description |
|---|---|
qn_getBlockFromTimestamp | Find block closest to a Unix timestamp |
qn_getBlocksInTimestampRange | List blocks within a timestamp range |
qn_getBlockWithReceipts | Get block data with all transaction receipts |
qn_getReceipts | Batch-fetch receipts for a block |
qn_broadcastRawTransaction | Multi-region transaction broadcast |
qn_resolveENS | Resolve ENS name to address (and reverse) |
qn_sendRawTransactionWithWebhook | Send transaction and receive webhook notification |
qn_fetchNFTs | Fetch NFTs owned by an address |
qn_fetchNFTCollectionDetails | Get collection-level metadata |
qn_fetchNFTsByCollection | Fetch NFTs from a specific collection |
qn_getTokenMetadataByContractAddress | Token metadata by contract |
qn_getTokenMetadataBySymbol | Token metadata by symbol |
qn_getWalletTokenBalance | All ERC-20 balances for a wallet |
qn_getWalletTokenTransactions | Token transfer history for a wallet |
qn_getTransactionsByAddress | Transaction history for an address |
qn_getTransfersByNFT | Transfer history for an NFT |
qn_verifyNFTsOwner | Verify NFT ownership |
Beacon Chain REST Endpoints
Beacon Chain data is accessible via REST endpoints on Ethereum endpoints.
| Category | Endpoints |
|---|---|
| Blobs | GET /eth/v1/beacon/blob_sidecars/{block_id}, GET /eth/v1/beacon/blobs/{block_id} |
| Blocks | GET /eth/v2/beacon/blocks/{block_id}, GET /eth/v1/beacon/blocks/{block_id}/root, GET /eth/v1/beacon/headers, GET /eth/v1/beacon/headers/{block_id} |
| State | GET /eth/v1/beacon/states/{state_id}/root, GET /eth/v1/beacon/states/{state_id}/fork, GET /eth/v1/beacon/states/{state_id}/finality_checkpoints |
| Validators | GET /eth/v1/beacon/states/{state_id}/validators, GET /eth/v1/beacon/states/{state_id}/validators/{validator_id}, GET /eth/v1/beacon/states/{state_id}/validator_balances, GET /eth/v1/beacon/states/{state_id}/committees, GET /eth/v1/beacon/states/{state_id}/sync_committees |
| Pending | GET /eth/v1/beacon/states/{state_id}/pending_deposits, GET /eth/v1/beacon/states/{state_id}/pending_consolidations |
| Rewards | POST /eth/v1/beacon/rewards/attestations/{epoch}, GET /eth/v1/beacon/rewards/blocks/{block_id}, POST /eth/v1/beacon/rewards/sync_committee/{block_id} |
| Pool | GET /eth/v1/beacon/pool/voluntary_exits |
| Config | GET /eth/v1/beacon/genesis, GET /eth/v1/config/deposit_contract, GET /eth/v1/config/fork_schedule, GET /eth/v1/config/spec |
| Validator Duties | POST /eth/v1/validator/duties/attester/{epoch}, GET /eth/v1/validator/duties/proposer/{epoch}, POST /eth/v1/validator/duties/sync/{epoch}, GET /eth/v1/validator/blinded_blocks/{slot}, GET /eth/v1/validator/sync_committee_contribution |
| Events | GET /eth/v1/events (SSE: head, block, attestation, voluntary_exit, finalized_checkpoint, chain_reorg) |
| Node | GET /eth/v1/node/peer_count, GET /eth/v1/node/peers, GET /eth/v1/node/syncing, GET /eth/v1/node/version |
| Debug | GET /eth/v1/debug/beacon/data_column_sidecars/{block_id}, GET /eth/v2/debug/beacon/states/{state_id} |
Solana RPC Methods
Standard Methods
| Category | Methods |
|---|---|
| Account | getAccountInfo, getMultipleAccounts, getProgramAccounts, getLargestAccounts, getMinimumBalanceForRentExemption |
| Balance | getBalance, getTokenAccountBalance, getTokenAccountsByOwner, getTokenAccountsByDelegate, getTokenLargestAccounts, getTokenSupply |
| Block | getBlock, getBlockCommitment, getBlockHeight, getBlockProduction, getBlocks, getBlocksWithLimit, getBlockTime, getFirstAvailableBlock |
| Transaction | getTransaction, getParsedTransaction, getTransactionCount, getSignaturesForAddress, getSignatureStatuses, simulateTransaction, sendTransaction |
| Slot | getSlot, getSlotLeader, getSlotLeaders, getHighestSnapshotSlot, getMaxRetransmitSlot, getMaxShredInsertSlot |
| Fees | getFeeForMessage, getRecentPrioritizationFees |
| Epoch & Inflation | getEpochInfo, getEpochSchedule, getInflationGovernor, getInflationRate, getInflationReward, getLeaderSchedule |
| Network | getClusterNodes, getHealth, getIdentity, getVersion, getGenesisHash, getSupply, getVoteAccounts, getStakeMinimumDelegation, getRecentPerformanceSamples, minimumLedgerSlot |
| Utility | isBlockhashValid, requestAirdrop (testnet/devnet only) |
Code Examples
Get balance and account info:
import { createSolanaRpc } from '@solana/kit';
import { address } from '@solana/addresses';
const rpc = createSolanaRpc(process.env.QUICKNODE_RPC_URL!);
const balance = await rpc.getBalance(address('vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg')).send();
// balance.value: bigint (lamports)
const accountInfo = await rpc.getAccountInfo(address('vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg'), {
encoding: 'base64',
}).send();
// accountInfo.value: { data, executable, lamports, owner, rentEpoch }Send transaction:
import { createSolanaRpc } from '@solana/kit';
const rpc = createSolanaRpc(process.env.QUICKNODE_RPC_URL!);
// Transaction must be signed before sending
const signature = await rpc.sendTransaction(signedTransactionBytes, {
encoding: 'base64',
skipPreflight: false,
preflightCommitment: 'confirmed',
}).send();
// signature: base-58 encoded transaction signatureGet program accounts (with filters):
import { createSolanaRpc } from '@solana/kit';
const rpc = createSolanaRpc(process.env.QUICKNODE_RPC_URL!);
const accounts = await rpc.getProgramAccounts(
address('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
{
encoding: 'base64',
filters: [
{ dataSize: 165n }, // Token account size
{ memcmp: { offset: 32n, bytes: 'OwnerPubkeyBase58...' as `${string}`, encoding: 'base58' } },
],
}
).send();
// accounts: Array of { pubkey, account: { data, executable, lamports, owner } }WebSocket Subscriptions
| Subscription | Description |
|---|---|
accountSubscribe | Monitor changes to a specific account |
programSubscribe | Monitor all accounts owned by a program |
logsSubscribe | Subscribe to transaction log output |
signatureSubscribe | Track confirmation of a specific transaction |
slotSubscribe | Monitor slot progression |
blockSubscribe | Track new confirmed/finalized blocks |
rootSubscribe | Receive root slot notifications |
slotsUpdatesSubscribe | Detailed slot update notifications |
import { createSolanaRpcSubscriptions } from '@solana/kit';
import { address } from '@solana/addresses';
const rpcSubscriptions = createSolanaRpcSubscriptions(process.env.QUICKNODE_WSS_URL!);
// Subscribe to account changes
const accountNotifications = await rpcSubscriptions
.accountNotifications(address('AccountPubkey...'), { commitment: 'confirmed' })
.subscribe({ abortSignal: AbortSignal.timeout(60_000) });
for await (const notification of accountNotifications) {
console.log('Account changed:', notification.value.lamports);
}Solana-Specific Add-on Methods
| Category | Methods |
|---|---|
| Priority Fees | qn_estimatePriorityFees |
| DAS (Digital Asset Standard) | getAsset, getAssets, getAssetProof, getAssetProofs, getAssetsByOwner, getAssetsByCreator, getAssetsByAuthority, getAssetsByGroup, getAssetSignatures, getTokenAccounts, getNftEditions, searchAssets |
| Jito Bundles | sendBundle, getBundleStatuses, getInflightBundleStatuses, simulateBundle, getTipAccounts, getTipFloor, getRegions |
| Jito Transaction | sendTransaction (Jito-routed) |
| Metis (Jupiter) | /quote, /swap, /swap-instructions, /tokens, /price, /new-pools, /program-id-to-label |
| Metis Limit Orders | /limit-orders/{pubkey}, /limit-orders/create, /limit-orders/cancel, /limit-orders/fee, /limit-orders/history, /limit-orders/open |
| Metis Pump.fun | /pump-fun/quote, /pump-fun/swap, /pump-fun/swap-instructions |
Bitcoin RPC Methods
Standard Methods
| Category | Methods |
|---|---|
| Blockchain | getbestblockhash, getblock, getblockchaininfo, getblockcount, getblockhash, getblockheader, getblockstats, getchaintips, getchaintxstats |
| Transaction | getrawtransaction, decoderawtransaction, decodescript, sendrawtransaction, gettxout, gettxoutproof, gettxoutsetinfo, testmempoolaccept, submitpackage |
| Mempool | getrawmempool, getmempoolancestors, getmempooldescendants, getmempoolinfo |
| Mining & Network | getdifficulty, getmininginfo, estimatesmartfee, getconnectioncount, getnetworkinfo, getmemoryinfo, getindexinfo |
| Validation | validateaddress, verifymessage |
Code Examples
Get block count and block data:
// Get current block height
const blockCount = await btcRpc('getblockcount');
console.log('Block height:', blockCount);
// Get block hash for a specific height
const blockHash = await btcRpc('getblockhash', [blockCount]);
// Get full block data (verbosity 2 = include decoded transactions)
const block = await btcRpc('getblock', [blockHash, 2]);
console.log('Block:', {
hash: block.hash,
height: block.height,
time: block.time,
nTx: block.nTx,
size: block.size,
});Get raw transaction:
// Get decoded transaction (verbose = true)
const tx = await btcRpc('getrawtransaction', [
'txid...',
true, // verbose: return JSON object instead of hex
]);
console.log('Transaction:', {
txid: tx.txid,
size: tx.size,
vout: tx.vout.map((o: any) => ({ value: o.value, address: o.scriptPubKey?.address })),
});Ordinals, Runes & Blockbook
| Category | Methods |
|---|---|
| Ordinals | ord_getInscription, ord_getInscriptions, ord_getInscriptionsByBlock, ord_getContent, ord_getMetadata, ord_getChildren, ord_getCollections, ord_getInscriptionRecursive |
| Sats | ord_getSat, ord_getSatAtIndex, ord_getSatRecursive |
| Runes | ord_getRune, ord_getRunes |
| Ordinals Utility | ord_getBlockHash, ord_getBlockInfo, ord_getCurrentBlockHash, ord_getCurrentBlockHeight, ord_getCurrentBlockTime, ord_getOutput, ord_getStatus, ord_getTx |
| Quicknode | qn_getBlockFromTimestamp, qn_getBlocksInTimestampRange |
| Blockbook | bb_getAddress, bb_getBalanceHistory, bb_getBlock, bb_getBlockHash, bb_getTx, bb_getTxSpecific, bb_getUTXOs, bb_getXPUB, bb_getTickers, bb_getTickersList |
WebSocket Patterns
EVM Subscriptions
| Type | Description |
|---|---|
newHeads | New block headers as they are mined |
logs | Log entries matching a filter (address, topics) |
newPendingTransactions | Transaction hashes entering the mempool |
syncing | Node sync status changes |
import { WebSocketProvider } from 'ethers';
const wsProvider = new WebSocketProvider(process.env.QUICKNODE_WSS_URL!);
// Subscribe to new blocks
wsProvider.on('block', (blockNumber) => {
console.log('New block:', blockNumber);
});
// Subscribe to pending transactions
wsProvider.on('pending', (txHash) => {
console.log('Pending tx:', txHash);
});
// Subscribe to contract events
const filter = {
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'], // Transfer
};
wsProvider.on(filter, (log) => {
console.log('Transfer event:', log);
});Solana Subscriptions
See the Solana WebSocket Subscriptions table above. Use @solana/kit's createSolanaRpcSubscriptions for typed subscription handling.
Batch Requests
JSON-RPC supports sending multiple calls in a single HTTP request by wrapping them in an array. This reduces round trips and is ideal for reading multiple pieces of data at once.
const response = await fetch(process.env.QUICKNODE_RPC_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([
{ jsonrpc: '2.0', id: 1, method: 'eth_blockNumber', params: [] },
{ jsonrpc: '2.0', id: 2, method: 'eth_gasPrice', params: [] },
{ jsonrpc: '2.0', id: 3, method: 'eth_getBalance', params: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 'latest'] },
]),
});
const results = await response.json();
// results: Array of { jsonrpc, id, result } in request order
// results[0].result: block number (hex)
// results[1].result: gas price (hex)
// results[2].result: balance (hex)Batch requests work the same way for Bitcoin (getblockcount, getbestblockhash, etc.) and any JSON-RPC endpoint. Solana also supports batching via the standard JSON-RPC interface.
Best Practices
1. Use WebSocket for subscriptions — HTTP polling wastes requests and adds latency. Use wss:// endpoints for real-time data (new blocks, pending transactions, account changes). 2. Batch read requests — Combine multiple eth_getBalance, eth_call, or similar reads into a single batch request to reduce round trips and credit usage. 3. Cache immutable data — Block data, transaction receipts, and finalized results never change. Cache them locally to avoid redundant calls. 4. Retry with exponential backoff — On 429 (rate limit) or network errors, retry with increasing delays: 1s, 2s, 4s, up to 30s max. 5. Use archive endpoints for historical data — Queries against old blocks require archive mode. Enable it on your Quicknode endpoint if you need eth_getBalance at historical blocks or Solana snapshots beyond the current epoch. 6. Set Solana commitment levels appropriately — Use confirmed for most reads, finalized when irreversibility matters (e.g., payment verification), and processed only when you need lowest latency and can handle rollbacks. 7. Consult chain-specific llms.txt for method details — Each chain has detailed per-method documentation at https://www.quicknode.com/docs/{chain}/llms.txt (e.g., ethereum, solana, bitcoin).
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
Method not found | Method not available on your plan or endpoint type | Check method availability in the chain docs; some methods require add-ons or archive mode |
429 Too Many Requests | Rate limit exceeded | Implement backoff/retry; batch requests; upgrade plan if persistent |
execution reverted | Smart contract call failed | Check the to address, data encoding, and block tag; use eth_estimateGas first to catch revert reasons |
Empty eth_getLogs result | Block range too narrow, wrong address, or wrong topics | Widen the block range; verify the contract address and topic hashes; check the chain |
Solana blockhash expired | Transaction submitted too late after fetching blockhash | Fetch a fresh blockhash immediately before signing; use isBlockhashValid to check |
Bitcoin Work queue depth exceeded | Too many concurrent requests | Reduce concurrency; add request queuing with rate limiting |
| WebSocket disconnects | Idle timeout or server maintenance | Implement automatic reconnection with exponential backoff; send periodic pings |
Documentation
Chain-Specific Docs
- Ethereum: https://www.quicknode.com/docs/ethereum
- Solana: https://www.quicknode.com/docs/solana
- Bitcoin: https://www.quicknode.com/docs/bitcoin
- Polygon: https://www.quicknode.com/docs/polygon
- Arbitrum: https://www.quicknode.com/docs/arbitrum
- Base: https://www.quicknode.com/docs/base
- Full Chain List: https://www.quicknode.com/chains
LLM-Optimized Documentation (llms.txt)
- Platform Overview: https://www.quicknode.com/llms.txt
- Docs Index: https://www.quicknode.com/docs/llms.txt
- Ethereum Methods: https://www.quicknode.com/docs/ethereum/llms.txt
- Solana Methods: https://www.quicknode.com/docs/solana/llms.txt
- Bitcoin Methods: https://www.quicknode.com/docs/bitcoin/llms.txt
- Pattern:
https://www.quicknode.com/docs/{chain}/llms.txt
Guides
- Quicknode Guides: https://www.quicknode.com/guides
Related References
- SDK Reference — Quicknode SDK with typed client methods
- Marketplace Add-ons — Token API, NFT API, DAS, Jito, trace/debug
- Yellowstone gRPC — Solana Geyser streaming via gRPC
Quicknode SDK Reference
The Quicknode SDK provides a type-safe JavaScript/TypeScript client for interacting with Quicknode services.
Installation
npm install @quicknode/sdkCore Setup
import { Core } from '@quicknode/sdk';
const core = new Core({
endpointUrl: process.env.QUICKNODE_RPC_URL!,
});Configuration Options
const core = new Core({
// Required: Your Quicknode endpoint URL
endpointUrl: process.env.QUICKNODE_RPC_URL!,
// Optional: Chain ID (auto-detected from endpoint)
chain: 1,
// Optional: Request timeout in milliseconds
timeout: 30000,
// Optional: Custom fetch implementation
fetch: customFetch,
// Optional: Custom headers
headers: {
'X-Custom-Header': 'value'
}
});Standard RPC Methods
Ethereum/EVM
// Get balance
const balance = await core.client.getBalance({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
});
// Get block
const block = await core.client.getBlock({
blockNumber: 'latest'
});
// Get transaction
const tx = await core.client.getTransaction({
hash: '0xTransactionHash...'
});
// Get transaction receipt
const receipt = await core.client.getTransactionReceipt({
hash: '0xTransactionHash...'
});
// Call contract
const result = await core.client.call({
to: '0xContractAddress...',
data: '0xFunctionSelector...'
});
// Estimate gas
const gas = await core.client.estimateGas({
from: '0xSender...',
to: '0xRecipient...',
value: '0x0'
});
// Get logs
const logs = await core.client.getLogs({
address: '0xContractAddress...',
fromBlock: 18000000,
toBlock: 'latest',
topics: ['0xEventSignature...']
});Token API Methods
Requires Token API add-on enabled.
qn_getWalletTokenBalance
const tokenBalances = await core.client.qn_getWalletTokenBalance({
wallet: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
contracts: [] // Empty for all tokens, or specify addresses
});
console.log('Tokens:', tokenBalances.assets);qn_getTokenMetadataByContractAddress
const metadata = await core.client.qn_getTokenMetadataByContractAddress({
contract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
});
console.log(`${metadata.name} (${metadata.symbol})`);qn_getTokenMetadataBySymbol
const metadata = await core.client.qn_getTokenMetadataBySymbol({
symbol: 'USDC'
});NFT API Methods
Requires NFT API add-on enabled.
qn_fetchNFTs
const nfts = await core.client.qn_fetchNFTs({
wallet: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
page: 1,
perPage: 10,
contracts: [] // Optional: filter by contracts
});
console.log(`Total NFTs: ${nfts.totalItems}`);
nfts.assets.forEach(nft => {
console.log(`${nft.name} - ${nft.collectionName}`);
});qn_fetchNFTCollectionDetails
const collections = await core.client.qn_fetchNFTCollectionDetails({
contracts: [
'0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
'0x60E4d786628Fea6478F785A6d7e704777c86a7c6'
]
});
collections.forEach(collection => {
console.log(`${collection.name}: ${collection.totalSupply} items`);
});qn_fetchNFTsByCollection
const collectionNFTs = await core.client.qn_fetchNFTsByCollection({
collection: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
tokens: ['1', '2', '3'], // Optional: specific token IDs
page: 1,
perPage: 10
});qn_verifyNFTsOwner
const verification = await core.client.qn_verifyNFTsOwner({
wallet: '0xOwnerAddress...',
contracts: [
{
address: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
tokenIds: ['1234', '5678']
}
]
});
console.log('Owns NFTs:', verification.owner);Multi-Chain Setup
import { Core } from '@quicknode/sdk';
// Create clients for multiple chains
const chains = {
ethereum: new Core({
endpointUrl: 'https://eth-endpoint.quiknode.pro/KEY/'
}),
polygon: new Core({
endpointUrl: 'https://polygon-endpoint.quiknode.pro/KEY/'
}),
arbitrum: new Core({
endpointUrl: 'https://arbitrum-endpoint.quiknode.pro/KEY/'
}),
base: new Core({
endpointUrl: 'https://base-endpoint.quiknode.pro/KEY/'
})
};
// Use appropriate chain
async function getBalance(chain: keyof typeof chains, address: string) {
return chains[chain].client.getBalance({ address });
}
const ethBalance = await getBalance('ethereum', '0x...');
const polyBalance = await getBalance('polygon', '0x...');Custom RPC Calls
For methods not directly exposed by the SDK:
// Generic request method
const result = await core.client.request({
method: 'trace_transaction',
params: ['0xTransactionHash...']
});
// Or use raw fetch
const response = await fetch(core.config.endpointUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'debug_traceTransaction',
params: ['0xTransactionHash...', { tracer: 'callTracer' }]
})
});Error Handling
import { Core, QuicknodeError } from '@quicknode/sdk';
const core = new Core({
endpointUrl: process.env.QUICKNODE_RPC_URL!
});
try {
const balance = await core.client.getBalance({
address: '0x...'
});
} catch (error) {
if (error instanceof QuicknodeError) {
console.error('Quicknode Error:', error.message);
console.error('Code:', error.code);
console.error('Details:', error.data);
} else {
throw error;
}
}TypeScript Types
import type {
GetBalanceParams,
GetBalanceResult,
GetBlockParams,
GetBlockResult,
QnFetchNFTsParams,
QnFetchNFTsResult,
QnGetWalletTokenBalanceParams,
QnGetWalletTokenBalanceResult
} from '@quicknode/sdk';
// Use types for better IDE support
const params: QnFetchNFTsParams = {
wallet: '0x...',
page: 1,
perPage: 10
};
const result: QnFetchNFTsResult = await core.client.qn_fetchNFTs(params);Common Patterns
Batch Balance Check
async function getMultipleBalances(addresses: string[]) {
const balancePromises = addresses.map(address =>
core.client.getBalance({ address })
);
const balances = await Promise.all(balancePromises);
return addresses.map((address, index) => ({
address,
balance: balances[index]
}));
}Token Portfolio
async function getPortfolio(wallet: string) {
const [ethBalance, tokens, nfts] = await Promise.all([
core.client.getBalance({ address: wallet }),
core.client.qn_getWalletTokenBalance({ wallet, contracts: [] }),
core.client.qn_fetchNFTs({ wallet, page: 1, perPage: 100 })
]);
return {
eth: ethBalance,
tokens: tokens.assets,
nfts: nfts.assets,
nftCount: nfts.totalItems
};
}Retry with Backoff
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = 1000
): Promise<T> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries - 1) throw error;
const delay = baseDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Max retries exceeded');
}
// Usage
const balance = await withRetry(() =>
core.client.getBalance({ address: '0x...' })
);Caching Layer
const cache = new Map<string, { data: any; timestamp: number }>();
const CACHE_TTL = 60000; // 1 minute
async function cachedCall<T>(
key: string,
fn: () => Promise<T>
): Promise<T> {
const cached = cache.get(key);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data as T;
}
const data = await fn();
cache.set(key, { data, timestamp: Date.now() });
return data;
}
// Usage
const balance = await cachedCall(
`balance:${address}`,
() => core.client.getBalance({ address })
);Browser Usage
<script type="module">
import { Core } from 'https://esm.sh/@quicknode/sdk';
const core = new Core({
endpointUrl: process.env.QUICKNODE_RPC_URL!
});
const balance = await core.client.getBalance({
address: '0x...'
});
console.log('Balance:', balance);
</script>Node.js Best Practices
import { Core } from '@quicknode/sdk';
// Use environment variables for API keys
const core = new Core({
endpointUrl: process.env.QUICKNODE_ENDPOINT_URL!
});
// Graceful shutdown
process.on('SIGTERM', async () => {
// Cleanup if needed
process.exit(0);
});Documentation
- SDK Overview: https://www.quicknode.com/docs/quicknode-sdk
- npm Package: https://www.npmjs.com/package/@quicknode/sdk
- Guides: https://www.quicknode.com/guides/tags/quicknode-sdk
Solana DAS API (Digital Asset Standard) Reference
The Metaplex Digital Asset Standard (DAS) API is a comprehensive service for querying Solana digital assets efficiently. It supports standard and compressed NFTs, fungible tokens, MPL Core Assets, and Token 2022 Assets.
Docs: https://www.quicknode.com/docs/solana/solana-das-api
Prerequisites
Enable the Metaplex Digital Asset Standard (DAS) API add-on on your QuickNode Solana endpoint via the Marketplace.
Methods Overview
| Method | Description |
|---|---|
getAsset | Get metadata for a single asset |
getAssets | Get metadata for multiple assets in one call |
getAssetProof | Get Merkle proof for a compressed asset |
getAssetProofs | Get Merkle proofs for multiple compressed assets |
getAssetsByAuthority | List assets controlled by an authority |
getAssetsByCreator | List assets by creator address |
getAssetsByGroup | List assets by group (e.g., collection) |
getAssetsByOwner | List assets owned by a wallet |
getAssetSignatures | Get transaction signatures for compressed assets |
getTokenAccounts | List token accounts by mint or owner |
getNftEditions | Get edition details of a master NFT |
searchAssets | Search assets with flexible filters |
Supported Asset Types
- Standard NFTs — traditional Solana NFTs
- Compressed NFTs (cNFTs) — Merkle tree-based, cost-efficient NFTs
- Fungible Tokens — SPL tokens
- MPL Core Assets — single-account design NFTs
- Token 2022 Assets — tokens using the Token Extensions program
getAsset
Retrieve metadata for a single asset by its mint address.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAsset',
params: {
id: '9ARngHhVaCtH5JFieRdSS5Y8cdZk2TMF4tfGSWFB9iSK',
options: {
showFungible: true,
showCollectionMetadata: true
}
}
})
});
const { result } = await response.json();
// result.content — metadata (name, description, image, attributes)
// result.ownership — owner, delegate, frozen status
// result.compression — tree, leaf, proof info (if compressed)
// result.royalty — royalty model, basis points, creators
// result.creators — array of creator addresses with verified status
// result.supply — edition/print supply infoParameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The asset mint address |
options.showFungible | boolean | No | Include fungible token info |
options.showCollectionMetadata | boolean | No | Include collection metadata |
options.showUnverifiedCollections | boolean | No | Include unverified collections |
getAssets
Fetch metadata for multiple assets in a single request.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssets',
params: {
ids: [
'9ARngHhVaCtH5JFieRdSS5Y8cdZk2TMF4tfGSWFB9iSK',
'BwJHge5FmE5RBkmWPoKzCWwxZFXsnqCMKHiiibXPJias'
]
}
})
});
const { result } = await response.json();
// result.items — array of asset metadata objectsgetAssetProof
Get the Merkle proof for a compressed asset. Required for transferring or modifying compressed NFTs on-chain.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetProof',
params: {
id: 'D85MZkvir9yQZFDHt8U2ZmS7D3LXKdiSjvw2MBdscJJa'
}
})
});
const { result } = await response.json();
// result.root — Merkle tree root hash
// result.proof — array of proof nodes
// result.node_index — index in the tree
// result.leaf — leaf hash
// result.tree_id — Merkle tree addressgetAssetProofs
Retrieve Merkle proofs for multiple compressed assets in one call.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetProofs',
params: {
ids: [
'D85MZkvir9yQZFDHt8U2ZmS7D3LXKdiSjvw2MBdscJJa',
'AnotherCompressedAssetMint...'
]
}
})
});
const { result } = await response.json();
// result — object keyed by asset ID, each containing root, proof, node_index, leaf, tree_idgetAssetsByOwner
List all digital assets owned by a wallet address.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetsByOwner',
params: {
ownerAddress: 'E645TckHQnDcavVv92Etc6xSWQaq8zzPtPRGBheviRAk',
limit: 10,
sortBy: { sortBy: 'recent_action', sortDirection: 'desc' },
options: {
showFungible: true,
showCollectionMetadata: true
}
}
})
});
const { result } = await response.json();
// result.total — total assets owned
// result.items — array of asset metadata objects
// result.cursor — use in next request for paginationParameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
ownerAddress | string | Yes | Wallet address |
limit | integer | No | Max results per page |
page | integer | No | Page number (page-based pagination) |
cursor | string | No | Cursor from previous response (cursor-based pagination) |
before / after | string | No | Range-based pagination |
sortBy | object | No | `{ sortBy: "created" \ |
options.showFungible | boolean | No | Include fungible tokens |
options.showCollectionMetadata | boolean | No | Include collection metadata |
getAssetsByCreator
List assets created by a specific address.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetsByCreator',
params: {
creatorAddress: '3pMvTLUA9NzZQd4gi725p89mvND1wRNQM3C8XEv1hTdA',
limit: 10
}
})
});
const { result } = await response.json();
// result.total, result.items, result.cursorgetAssetsByGroup
List assets by group identifier (e.g., collection address).
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetsByGroup',
params: {
groupKey: 'collection',
groupValue: 'CollectionMintAddress...',
limit: 10
}
})
});
const { result } = await response.json();
// result.total, result.items, result.cursorgetAssetsByAuthority
List assets controlled by a specific authority.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetsByAuthority',
params: {
authorityAddress: 'AuthorityPubkey...',
limit: 10
}
})
});
const { result } = await response.json();
// result.total, result.items, result.cursorgetAssetSignatures
Get transaction signatures associated with a compressed asset.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetSignatures',
params: {
id: 'CompressedAssetMint...',
limit: 10
}
})
});
const { result } = await response.json();
// result.items — array of transaction signature objectsgetTokenAccounts
List token accounts and balances by mint address or owner address. Useful for finding all holders of a token or all tokens held by a wallet.
// By mint address — find holders of a token
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getTokenAccounts',
params: {
mintAddress: 'So11111111111111111111111111111111111111112',
limit: 10
}
})
});
const { result } = await response.json();
// result.total — total token accounts
// result.token_accounts — array of accounts with:
// address, mint, owner, amount, delegated_amount, frozen// By owner address — find all tokens held by a wallet
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getTokenAccounts',
params: {
ownerAddress: 'WalletPubkey...',
limit: 10
}
})
});getNftEditions
Retrieve edition details for a master NFT, including all printed editions.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getNftEditions',
params: {
mintAddress: 'MasterEditionMint...',
limit: 10
}
})
});
const { result } = await response.json();
// result.items — array of edition detailssearchAssets
Search for assets using flexible filter criteria. The most powerful query method in the DAS API.
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'searchAssets',
params: {
ownerAddress: 'WalletPubkey...',
compressed: true,
limit: 10,
sortBy: { sortBy: 'recent_action', sortDirection: 'desc' }
}
})
});
const { result } = await response.json();
// result.total, result.items, result.cursorSearch Filter Parameters:
| Parameter | Type | Description |
|---|---|---|
ownerAddress | string | Filter by asset owner |
creatorAddress | string | Filter by creator |
authorityAddress | string | Filter by authority |
grouping | array | Filter by group (e.g., [["collection", "address"]]) |
delegateAddress | string | Filter by delegate |
compressed | boolean | Filter by compression status |
compressible | boolean | Filter by compressibility |
frozen | boolean | Filter by frozen status |
burnt | boolean | Filter by burn status |
supply | integer | Filter by supply amount |
supplyMint | string | Filter by supply mint |
interface | string | Filter by asset interface type |
ownerType | string | Filter by owner type |
royaltyTargetType | string | Filter by royalty target type |
royaltyTarget | string | Filter by royalty recipient |
royaltyAmount | integer | Filter by royalty basis points |
jsonUri | string | Filter by metadata URI |
negate | boolean | Invert filter logic |
conditionType | string | Condition type for filters |
Sorting & Pagination:
| Parameter | Type | Description |
|---|---|---|
sortBy | object | `{ sortBy: "created" \ |
limit | integer | Max results per page |
page | integer | Page number |
cursor | string | Cursor for next page |
before / after | string | Range-based pagination |
showFungible | boolean | Include fungible tokens |
showCollectionMetadata | boolean | Include collection metadata |
Pagination
The DAS API supports three pagination modes:
Page-based — simple numbered pages:
{ page: 1, limit: 100 }Cursor-based — use cursor from previous response (recommended for large datasets):
{ cursor: 'previousResponse.result.cursor', limit: 100 }Range-based — before/after asset identifiers:
{ before: 'assetId', after: 'assetId', limit: 100 }Common Use Cases
Get all NFTs in a collection
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetsByGroup',
params: {
groupKey: 'collection',
groupValue: 'CollectionMintAddress...',
limit: 100
}
})
});Get all compressed NFTs owned by a wallet
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'searchAssets',
params: {
ownerAddress: 'WalletPubkey...',
compressed: true,
limit: 100
}
})
});Transfer a compressed NFT (get proof first)
// 1. Get the asset proof
const proofResponse = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAssetProof',
params: { id: 'CompressedNftMint...' }
})
});
const { result: proof } = await proofResponse.json();
// 2. Get asset details
const assetResponse = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getAsset',
params: { id: 'CompressedNftMint...' }
})
});
const { result: asset } = await assetResponse.json();
// 3. Use proof.root, proof.proof, proof.node_index, and asset data
// to construct the transfer instruction via @metaplex-foundation/mpl-bubblegumGet all token holders for a mint
let cursor = null;
const allAccounts = [];
do {
const params = { mintAddress: 'TokenMint...', limit: 100 };
if (cursor) params.cursor = cursor;
const response = await fetch(process.env.QUICKNODE_RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getTokenAccounts',
params
})
});
const { result } = await response.json();
allAccounts.push(...result.token_accounts);
cursor = result.cursor;
} while (cursor);Documentation
- DAS API Overview: https://www.quicknode.com/docs/solana/solana-das-api
- getAsset: https://www.quicknode.com/docs/solana/getAsset
- getAssets: https://www.quicknode.com/docs/solana/getAssets
- getAssetProof: https://www.quicknode.com/docs/solana/getAssetProof
- getAssetProofs: https://www.quicknode.com/docs/solana/getAssetProofs
- getAssetsByAuthority: https://www.quicknode.com/docs/solana/getAssetsByAuthority
- getAssetsByCreator: https://www.quicknode.com/docs/solana/getAssetsByCreator
- getAssetsByGroup: https://www.quicknode.com/docs/solana/getAssetsByGroup
- getAssetsByOwner: https://www.quicknode.com/docs/solana/getAssetsByOwner
- getAssetSignatures: https://www.quicknode.com/docs/solana/getAssetSignatures
- getTokenAccounts: https://www.quicknode.com/docs/solana/getTokenAccounts
- getNftEditions: https://www.quicknode.com/docs/solana/getNftEditions
- searchAssets: https://www.quicknode.com/docs/solana/searchAssets
- Marketplace Add-on: https://marketplace.quicknode.com/add-on/metaplex-digital-asset-standard-api
x402 Reference
x402 enables pay-per-request RPC access via USDC micropayments. No API key or signup required — authenticate with SIWE (Ethereum) or SIWX (multi-chain including Solana), purchase credits with USDC, and access 140+ blockchain RPC endpoints.
Overview
| Property | Value |
|---|---|
| Protocol | HTTP 402 Payment Required |
| Payment Method | USDC on Base, Polygon, or Solana |
| Authentication | SIWE / SIWX (EVM + Solana) |
| Chains | 140+ (same as Quicknode RPC network) |
| Base URL | https://x402.quicknode.com |
| Use Cases | Keyless RPC access, AI agents, pay-as-you-go, ephemeral wallets |
How It Works
1. Authenticate — Sign a SIWE or SIWX message with your wallet to get a JWT session token 2. Make RPC calls — Send JSON-RPC requests to POST /:network with your JWT in the Authorization: Bearer header 3. Pay when prompted — When credits run out, the server returns HTTP 402. The @quicknode/x402 package automatically signs a USDC payment and retries 4. Repeat — Credits are consumed (1 per successful JSON-RPC response). When exhausted, another 402 triggers a new payment automatically
Key Endpoints
| Endpoint | Method | Description |
|---|---|---|
/auth | POST | Authenticate via SIWE/SIWX, returns JWT session token |
/credits | GET | Check credit balance |
/drip | POST | Testnet faucet — free credits (Base Sepolia only) |
/:network | POST | JSON-RPC request to a specific chain (e.g., /ethereum-mainnet) |
/:network/ws | WebSocket | WebSocket RPC connection to a specific chain |
/discovery/resources | GET | Bazaar-compatible catalog of all supported networks (public) |
Credit Pricing
| Environment | CAIP-2 Chain ID | Credits | Cost |
|---|---|---|---|
| Base Sepolia (testnet) | eip155:84532 | 100 | $0.01 USDC |
| Base Mainnet | eip155:8453 | 1,000,000 | $10 USDC |
| Polygon Amoy (testnet) | eip155:80002 | 100 | $0.01 USDC |
| Polygon Mainnet | eip155:137 | 1,000,000 | $10 USDC |
| Solana Devnet | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 | 100 | $0.01 USDC |
| Solana Mainnet | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | 1,000,000 | $10 USDC |
1 credit per successful JSON-RPC response. Error responses are not metered.
Recommended: @quicknode/x402 Package
The official @quicknode/x402 package handles SIWX authentication, x402 USDC payments, JWT session management, and reconnection automatically.
npm install @quicknode/x402import { createQuicknodeX402Client } from '@quicknode/x402';
const client = await createQuicknodeX402Client({
baseUrl: 'https://x402.quicknode.com',
network: 'eip155:84532', // pay on Base Sepolia (testnet)
evmPrivateKey: '0xYOUR_KEY',
preAuth: true, // handles auth, funding, and payments automatically
});
// client.fetch handles auth, SIWX, and payment automatically
const response = await client.fetch('https://x402.quicknode.com/base-sepolia', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'eth_blockNumber', params: [] }),
});`preAuth` option: When preAuth: true, the client performs SIWX authentication and obtains a JWT upfront before any RPC call. This means when a 402 occurs, it can immediately submit payment (auth → pay). Without preAuth, the client sees payment requirements first, then authenticates, then pays — an extra round-trip (pay requirements → auth → pay).
Alternative: @x402/fetch (Manual Setup)
For more control, use the lower-level @x402/fetch packages directly.
EVM Setup
npm install @x402/fetch @x402/evm viem siweimport { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';
import { SiweMessage, generateNonce } from 'siwe';
import { wrapFetchWithPayment, x402Client } from '@x402/fetch';
import { ExactEvmScheme, toClientEvmSigner } from '@x402/evm';
const BASE_URL = 'https://x402.quicknode.com';
// 1. Set up wallet
const walletClient = createWalletClient({
account: privateKeyToAccount('0xYOUR_PRIVATE_KEY'),
chain: baseSepolia,
transport: http(),
});
// 2. Authenticate with SIWE
const siweMessage = new SiweMessage({
domain: 'x402.quicknode.com',
address: walletClient.account.address,
statement: 'I accept the Quicknode Terms of Service: https://www.quicknode.com/terms',
uri: BASE_URL,
version: '1',
chainId: 84532,
nonce: generateNonce(),
issuedAt: new Date().toISOString(),
});
const message = siweMessage.prepareMessage();
const signature = await walletClient.signMessage({ message });
const authResponse = await fetch(`${BASE_URL}/auth`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message, signature }),
});
const { token } = await authResponse.json();
// 3. Create x402-enabled fetch
const evmSigner = toClientEvmSigner({
address: walletClient.account.address,
signTypedData: (params) => walletClient.signTypedData(params),
});
const client = new x402Client()
.register('eip155:84532', new ExactEvmScheme(evmSigner));
// IMPORTANT: @x402/fetch passes a Request object (not url+init) on payment
// retries. The inner fetch must handle both calling conventions.
const authedFetch = async (input: RequestInfo | URL, init?: RequestInit) => {
if (input instanceof Request) {
const req = input.clone();
req.headers.set('Authorization', `Bearer ${token}`);
return fetch(req);
}
const headers = new Headers(init?.headers);
headers.set('Authorization', `Bearer ${token}`);
return fetch(input, { ...init, headers });
};
const x402Fetch = wrapFetchWithPayment(authedFetch, client);
// 4. Make RPC calls — payment is automatic on 402
const response = await x402Fetch(`${BASE_URL}/base-sepolia`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'eth_blockNumber', params: [] }),
});Solana Setup
npm install @x402/fetch @x402/svm @solana/kit tweetnacl bs58import { createKeyPairSignerFromBytes } from '@solana/kit';
import { wrapFetchWithPayment, x402Client } from '@x402/fetch';
import { ExactSvmScheme } from '@x402/svm';
// Create a Solana signer from your secret key (64 bytes)
const signer = await createKeyPairSignerFromBytes(secretKey);
// Register the signer for Solana Devnet
const client = new x402Client()
.register('solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', new ExactSvmScheme(signer));
const x402Fetch = wrapFetchWithPayment(authedFetch, client);
const response = await x402Fetch('https://x402.quicknode.com/solana-devnet', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'getBlockHeight', params: [] }),
});Authentication
All endpoints except /auth and /discovery/resources require a JWT Bearer token. Three auth paths are supported:
Path 1: Legacy SIWE (EVM only)
POST /auth
{ "message": "<SIWE string>", "signature": "0x<hex>" }Path 2: SIWX/EVM
POST /auth
{ "message": "<SIWE string>", "signature": "0x<hex>", "type": "siwx" }Path 3: SIWX/Solana
POST /auth
{ "message": "<SIWS string>", "signature": "<Base58>", "type": "siwx" }SIWS message format (CAIP-122):
x402.quicknode.com wants you to sign in with your Solana account:
<Base58 address>
I accept the Quicknode Terms of Service: https://www.quicknode.com/terms
URI: https://x402.quicknode.com
Version: 1
Chain ID: EtWTRABZaYq6iMfeYKouRu166VU2xqa1
Nonce: <random 8+ chars>
Issued At: <ISO 8601 timestamp>Required message fields (all paths)
domain:x402.quicknode.comaddress: your wallet address (0x... for EVM, Base58 for Solana)statement:I accept the Quicknode Terms of Service: https://www.quicknode.com/termsuri:https://x402.quicknode.comversion:1chainId: See Credit Pricing table for supported chain IDsnonce: at least 8 random characters (single-use)issuedAt: current ISO 8601 timestamp (must be within 5 minutes)
Auth response
{ "token": "<JWT>", "expiresAt": "<ISO datetime>", "accountId": "<CAIP-10 ID>" }JWT expires in 1 hour. The auth chain determines payment method, not which networks you can query.
Extension-Based Authentication (SIWX Header)
For fully self-describing x402-native flows — no out-of-band knowledge of /auth needed:
1. Hit any endpoint with no auth — server returns 402 with extensions 2. Read the sign-in-with-x extension — contains SIWX challenge with domain, uri, nonce, issuedAt, supportedChains 3. Sign the challenge — construct SIWX message, sign, encode as SIGN-IN-WITH-X header (Base64 JSON) 4. Pay with USDC — include PAYMENT-SIGNATURE header. Settlement response contains JWT in quicknode-session extension 5. Extract JWT from extensions['quicknode-session'].info.token
Bootstrapping (No Existing Wallet)
EVM (Base Sepolia)
1. Generate wallet with generatePrivateKey() + privateKeyToAccount() from viem/accounts 2. Authenticate via SIWE → get JWT 3. Call POST /drip → receive free testnet USDC on Base Sepolia 4. Wait for USDC to arrive (poll via eth_call on a public RPC) 5. Make RPC calls — @quicknode/x402 with preAuth: true handles auth and payment negotiation; you still need to fund the wallet via /drip or transfer USDC manually
Solana
1. Generate Ed25519 keypair via @solana/kit or tweetnacl 2. Pre-fund with Solana Devnet USDC (mint: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU) — no /drip faucet for Solana 3. Authenticate via SIWX/Solana → get JWT 4. Make RPC calls with @x402/fetch + @x402/svm
Rate Limits
| Endpoint | Limit |
|---|---|
/auth | 10 requests / 10 seconds per IP |
/credits | 50 requests / 10 seconds per account |
/drip | 5 requests / 60 seconds per account |
/:network | 1,000 requests / 10 seconds per network:account pair |
Best Practices
1. Use `@quicknode/x402` for simplicity — handles auth, payments, and session management automatically 2. Use testnet first — Call /drip on Base Sepolia for free credits during development 3. Reuse JWT tokens — they last 1 hour, no need to re-authenticate per request 4. Monitor credits — check /credits periodically to anticipate top-ups 5. Auth chain ≠ query chain — authenticate on Base but query Solana, Ethereum, or any supported network 6. WebSocket for subscriptions — use /:network/ws for persistent connections
npm Packages
| Package | Purpose |
|---|---|
@quicknode/x402 | Official all-in-one client (recommended) |
@x402/fetch | Low-level fetch wrapper for 402 payment handling |
@x402/evm | EVM payment scheme (EIP-712 signing) |
@x402/svm | Solana payment scheme (SPL Token transfer) |
viem | Ethereum wallet client, signing, chain utilities |
siwe | Sign-In with Ethereum (EIP-4361) messages |
@solana/kit | Solana SDK for keypair signers |
Documentation
- x402 Platform: https://x402.quicknode.com
- x402 Documentation (llms.txt): https://x402.quicknode.com/llms.txt
- x402 Guide: https://www.quicknode.com/guides/x402/access-quicknode-endpoints-with-x402-payments
- Code Examples: https://github.com/quiknode-labs/qn-x402-examples
- x402 Protocol Spec: https://www.x402.org
Yellowstone gRPC Reference
Yellowstone gRPC is a high-performance Solana Geyser plugin that enables real-time blockchain data streaming through gRPC interfaces. Available as a Marketplace add-on on Quicknode.
Overview
| Property | Value |
|---|---|
| Protocol | gRPC (HTTP/2) |
| Port | 10000 |
| Package | @triton-one/yellowstone-grpc (TypeScript) |
| Compression | zstd supported |
| Commitment Levels | Processed, Confirmed, Finalized |
| Languages | TypeScript, Rust, Go, Python |
| Prerequisite | Enable Yellowstone Geyser gRPC add-on on your Quicknode endpoint |
Endpoint & Authentication
Endpoint Format
https://<endpoint-name>.solana-mainnet.quiknode.pro:10000Deriving Credentials
From your HTTP Provider URL:
https://example-guide-demo.solana-mainnet.quiknode.pro/123456789/- Endpoint:
https://example-guide-demo.solana-mainnet.quiknode.pro:10000 - Token:
123456789(the path segment after the endpoint name)
Installation
TypeScript
npm install @triton-one/yellowstone-grpcRust
[dependencies]
yellowstone-grpc-client = "11.0.0"
yellowstone-grpc-proto = "10.1.1"
tokio = { version = "1.28" }
futures = "0.3"Go
go get google.golang.org/grpc
go get google.golang.org/protobufDownload proto files (geyser.proto, solana-storage.proto) from the Yellowstone gRPC GitHub repo and compile with protoc.
Python
grpcio==1.63.0
grpcio-tools==1.63.0
protobuf==5.26.1
base58==2.1.1Generate stubs:
python -m grpc_tools.protoc \
-I./proto/ \
--python_out=./generated \
--pyi_out=./generated \
--grpc_python_out=./generated \
./proto/*Connection Setup
TypeScript
import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
const ENDPOINT = "https://example-guide-demo.solana-mainnet.quiknode.pro:10000";
const TOKEN = "123456789";
const client = new Client(ENDPOINT, TOKEN, {});Go
opts := []grpc.DialOption{
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: 10 * time.Second,
Timeout: time.Second,
PermitWithoutStream: true,
}),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(1024 * 1024 * 1024),
grpc.UseCompressor(gzip.Name),
),
grpc.WithPerRPCCredentials(tokenAuth{token: token}),
}
conn, err := grpc.Dial(endpoint, opts...)
client := pb.NewGeyserClient(conn)Python
import grpc
def create_grpc_channel(endpoint: str, token: str) -> grpc.Channel:
endpoint = endpoint.replace('http://', '').replace('https://', '')
auth_creds = grpc.metadata_call_credentials(
lambda context, callback: callback((("x-token", token),), None)
)
ssl_creds = grpc.ssl_channel_credentials()
combined_creds = grpc.composite_channel_credentials(ssl_creds, auth_creds)
return grpc.secure_channel(endpoint, credentials=combined_creds)
channel = create_grpc_channel(
"example-guide-demo.solana-mainnet.quiknode.pro:10000",
"123456789"
)
stub = geyser_pb2_grpc.GeyserStub(channel)Rust
use yellowstone_grpc_client::GeyserGrpcClient;
use tonic::transport::ClientTlsConfig;
let client = GeyserGrpcClient::build_from_shared(endpoint.to_string())?
.x_token(Some(token.to_string()))?
.tls_config(ClientTlsConfig::new().with_native_roots())?
.connect()
.await?;Subscribe Filter Types
The subscribe method accepts a SubscribeRequest with the following filter maps:
| Filter | Key | Description |
|---|---|---|
| accounts | SubscribeRequestFilterAccounts | Account data changes by pubkey, owner, or data filters |
| transactions | SubscribeRequestFilterTransactions | Transaction events with account/vote/failure filters |
| transactionsStatus | SubscribeRequestFilterTransactions | Lightweight transaction status updates (same filter shape) |
| slots | SubscribeRequestFilterSlots | Slot progression and status changes |
| blocks | SubscribeRequestFilterBlocks | Full block data with optional transaction/account inclusion |
| blocksMeta | SubscribeRequestFilterBlocksMeta | Block metadata without full contents |
| entry | SubscribeRequestFilterEntry | PoH entry updates |
Global options on the request:
| Field | Type | Description |
|---|---|---|
commitment | CommitmentLevel | PROCESSED (0), CONFIRMED (1), FINALIZED (2) |
accountsDataSlice | Array | Slice account data: { offset, length } |
ping | Object | Keepalive ping: { id } |
from_slot | uint64 | Replay from a specific slot |
Transaction Filter Options
| Field | Type | Description |
|---|---|---|
vote | bool (optional) | Include/exclude vote transactions |
failed | bool (optional) | Include/exclude failed transactions |
signature | string (optional) | Filter by specific transaction signature |
accountInclude | string[] | Include transactions involving these accounts |
accountExclude | string[] | Exclude transactions involving these accounts |
accountRequired | string[] | Require all listed accounts in the transaction |
Account Filter Options
| Field | Type | Description |
|---|---|---|
account | string[] | Filter by specific account pubkeys |
owner | string[] | Filter by owner program pubkeys |
filters | Array | Data filters: memcmp, datasize, token_account_state, lamports |
nonempty_txn_signature | bool (optional) | Only accounts with non-empty transaction signatures |
Account Data Filters
- memcmp: Match bytes at a specific offset (
{ offset, bytes | base58 | base64 }) - datasize: Match accounts with exact data size
- token_account_state: Match valid SPL token account state
- lamports: Compare lamport balance (
eq,ne,lt,gt)
Available Methods
| Method | Description | Parameters |
|---|---|---|
subscribe | Bidirectional stream for real-time data | SubscribeRequest (via stream) |
subscribeReplayInfo | Earliest available slot for replay | None |
getBlockHeight | Current block height | Optional CommitmentLevel |
getLatestBlockhash | Most recent blockhash | Optional CommitmentLevel |
getSlot | Current slot number | Optional CommitmentLevel |
getVersion | Geyser plugin version info | None |
isBlockhashValid | Check blockhash validity | blockhash (string), optional CommitmentLevel |
ping | Connection health check | count (integer) |
Subscription Examples
Account Updates
import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
const client = new Client(ENDPOINT, TOKEN, {});
const stream = await client.subscribe();
stream.on("data", (data) => {
if (data.account) {
const account = data.account;
console.log("Account updated:", {
pubkey: Buffer.from(account.account.pubkey).toString("hex"),
lamports: account.account.lamports,
slot: account.slot,
owner: Buffer.from(account.account.owner).toString("hex"),
});
}
});
stream.on("error", (error) => {
console.error("Stream error:", error);
});
await new Promise<void>((resolve, reject) => {
stream.write(
{
accounts: {
account_filter: {
account: ["ACCOUNT_PUBKEY"],
owner: [],
filters: [],
},
},
slots: {},
transactions: {},
transactionsStatus: {},
entry: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
ping: undefined,
commitment: CommitmentLevel.CONFIRMED,
},
(err) => {
if (err) reject(err);
else resolve();
}
);
});Transaction Streaming
import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
const client = new Client(ENDPOINT, TOKEN, {});
const stream = await client.subscribe();
stream.on("data", (data) => {
if (data.transaction) {
const txn = data.transaction;
console.log("Transaction:", {
signature: Buffer.from(txn.transaction.signature).toString("base64"),
slot: txn.slot,
isVote: txn.transaction.isVote,
});
}
});
await new Promise<void>((resolve, reject) => {
stream.write(
{
accounts: {},
slots: {},
transactions: {
txn_filter: {
vote: false,
failed: false,
accountInclude: ["PROGRAM_OR_ACCOUNT_PUBKEY"],
accountExclude: [],
accountRequired: [],
},
},
transactionsStatus: {},
entry: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
ping: undefined,
commitment: CommitmentLevel.CONFIRMED,
},
(err) => {
if (err) reject(err);
else resolve();
}
);
});Slot Updates
import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
const client = new Client(ENDPOINT, TOKEN, {});
const stream = await client.subscribe();
stream.on("data", (data) => {
if (data.slot) {
console.log("Slot:", {
slot: data.slot.slot,
parent: data.slot.parent,
status: data.slot.status,
});
}
});
await new Promise<void>((resolve, reject) => {
stream.write(
{
accounts: {},
slots: {
slot_filter: {
filterByCommitment: true,
},
},
transactions: {},
transactionsStatus: {},
entry: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
ping: undefined,
commitment: CommitmentLevel.CONFIRMED,
},
(err) => {
if (err) reject(err);
else resolve();
}
);
});Unary RPC Methods
import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
const client = new Client(ENDPOINT, TOKEN, {});
// Block height
const blockHeight = await client.getBlockHeight();
console.log("Block height:", blockHeight);
// Latest blockhash
const blockhash = await client.getLatestBlockhash(CommitmentLevel.CONFIRMED);
console.log("Blockhash:", blockhash);
// Current slot
const slot = await client.getSlot();
console.log("Slot:", slot);
// Version info
const version = await client.getVersion();
console.log("Version:", version);
// Validate blockhash
const valid = await client.isBlockhashValid(blockhash.blockhash);
console.log("Valid:", valid);
// Ping
const pong = await client.ping(1);
console.log("Pong:", pong);
// Replay info
const replayInfo = await client.subscribeReplayInfo({});
console.log("First available slot:", replayInfo.firstAvailable);Stream Handling
Async Iteration Pattern
const stream = await client.subscribe();
// Write subscription request
stream.write(subscribeRequest);
// Process updates
stream.on("data", (update) => {
if (update.account) handleAccount(update);
if (update.transaction) handleTransaction(update);
if (update.slot) handleSlot(update);
if (update.block) handleBlock(update);
if (update.blockMeta) handleBlockMeta(update);
if (update.entry) handleEntry(update);
if (update.pong) handlePong(update);
});
stream.on("error", (error) => {
console.error("Stream error:", error);
// Implement reconnection logic
});
stream.on("end", () => {
console.log("Stream ended");
// Implement reconnection logic
});Keepalive Pings
// Send periodic pings to keep the connection alive
const pingInterval = setInterval(() => {
stream.write({
ping: { id: Date.now() },
});
}, 10000); // every 10 seconds
// Clean up on stream end
stream.on("end", () => clearInterval(pingInterval));Reconnection with Backoff
async function connectWithRetry(maxRetries = 5) {
let attempt = 0;
while (attempt < maxRetries) {
try {
const client = new Client(ENDPOINT, TOKEN, {});
const stream = await client.subscribe();
stream.write(subscribeRequest);
return stream;
} catch (error) {
attempt++;
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
console.error(`Connection failed (attempt ${attempt}), retrying in ${delay}ms`);
await new Promise((r) => setTimeout(r, delay));
}
}
throw new Error("Max retries exceeded");
}Best Practices
1. Use narrow filters — Subscribe only to accounts, programs, or transaction patterns you need. Broad filters increase bandwidth and processing overhead. 2. Set appropriate commitment levels — Use CONFIRMED for most use cases. Use FINALIZED when you need irreversibility guarantees. Avoid PROCESSED unless you need the lowest latency and can handle rollbacks. 3. Implement reconnection logic — gRPC streams can drop due to network issues or server maintenance. Always implement exponential backoff reconnection. 4. Enable zstd compression — Reduces bandwidth significantly for high-throughput subscriptions. 5. Test on devnet first — Validate your filter logic and stream handling on devnet before deploying to mainnet. 6. Use `accountsDataSlice` — When you only need part of an account's data, slice it to reduce payload size.
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Connection refused on port 10000 | Yellowstone add-on not enabled | Enable the Yellowstone Geyser gRPC add-on in the Quicknode dashboard |
| Authentication failed | Invalid or missing token | Extract the token from your HTTP Provider URL (path segment after endpoint name) |
| No data received | Filters too restrictive or wrong commitment level | Start with broad filters and narrow down; check commitment level |
| Stream drops frequently | No keepalive pings | Send periodic pings (every 10s) and implement reconnection logic |
| Large payloads / high bandwidth | Subscribing to too much data | Narrow filters, use accountsDataSlice, enable zstd compression |
| Stale data | Using PROCESSED commitment | Switch to CONFIRMED or FINALIZED |
Documentation
- Yellowstone gRPC Overview: https://www.quicknode.com/docs/solana/yellowstone-grpc/overview
- Subscribe Method: https://www.quicknode.com/docs/solana/yellowstone-grpc/subscribe
- TypeScript Setup: https://www.quicknode.com/docs/solana/yellowstone-grpc/overview/typescript
- Go Setup: https://www.quicknode.com/docs/solana/yellowstone-grpc/overview/go
- Rust Setup: https://www.quicknode.com/docs/solana/yellowstone-grpc/overview/rust
- Python Setup: https://www.quicknode.com/docs/solana/yellowstone-grpc/overview/python
- Marketplace Add-on: https://marketplace.quicknode.com/add-on/yellowstone-grpc-geyser-plugin
- Guides: https://www.quicknode.com/guides/tags/geyser
Related skills
FAQ
Do I need a QuickNode account?
No; x402 lets any wallet with USDC pay per request with no signup, or you can use an API-key endpoint.
Which chains are supported?
Base, Ethereum, Polygon, Solana, and Unichain, all chains Bankr supports; QuickNode itself covers 77+ networks.