Public API
Networks
Networks routes describe what you can build on: which networks and environments exist, what a webhook or a block costs in credits, which RPC methods a network serves and what each costs, how the networks are doing right now, and which tokens a network accepts for payments. A network is named by its slug (for example ethereum, tron) and an environment by its own slug (mainnet, sepolia, nile). All routes require signed headers (see Authentication). Base URL: see Overview. Success responses use ok: true plus the fields below. A field without a value is not written (it is never null): read a missing field as "no value". Numeric ids are not exposed.
GET /v1/networks
Active networks, ordered by sort, with the slugs of their environments.
Response fields
| Name | Type | Description |
|---|---|---|
| ok | boolean | true on success. |
| networks[] | array | Networks, ordered by sort. |
| networks[].uuid | string | Network uuid. |
| networks[].name | string | Display name. |
| networks[].slug | string | Network slug (use it in paths and in network_slug). |
| networks[].sort | number | Sort order in the catalog. |
| networks[].environment_kinds | string[] | Slugs of the active environments (mainnet, testnets). |
| networks[].scan_environment_kinds | string[] | Environments where events and payments are available. Empty array when none. |
- Takes no query parameters or body. Only active networks and environments are listed.
- environment_kinds are the slugs of the active environments of the network (mainnet, sepolia, ...). The same slugs are used as env_slug when you create an RPC endpoint and as the environments in GET /v1/networks/{slug}/credits.
- scan_environment_kinds is the subset of environment_kinds where on-chain events (Address Watch, Tx Watch, Payments, block webhooks) are available. It is an empty array when none.
- A network is addressed by slug in the other routes; uuid is a stable public identifier.
Request example
import { createHash, createHmac } from 'node:crypto'
const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'
// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
const timestamp = Math.floor(Date.now() / 1000)
const bodyHash = createHash('sha256').update(body).digest('hex')
const signature = createHmac('sha256', SECRET)
.update([timestamp, method, path, bodyHash].join('\n'))
.digest('hex')
const res = await fetch(BASE + path, {
method,
headers: {
'X-Api-Key': API_KEY,
'X-Timestamp': String(timestamp),
'X-Signature': signature,
...(body ? { 'Content-Type': 'application/json' } : {}),
},
body: body || undefined,
})
return res.json()
}
console.log(await call('GET', '/api/public/v1/networks'))The request is signed in the snippet itself — see Authentication for the signing rules.
Response example
{
"ok": true,
"networks": [
{
"uuid": "6f1c2a52-8c0e-4f43-9a55-3c5b6a7d9e10",
"name": "Ethereum",
"slug": "ethereum",
"sort": 10,
"environment_kinds": ["mainnet", "sepolia", "hoodi"],
"scan_environment_kinds": ["mainnet", "sepolia"]
},
{
"uuid": "0c7d1e24-5d3b-4a37-b0a1-7a2e9c4f8d21",
"name": "TRON",
"slug": "tron",
"sort": 110,
"environment_kinds": ["mainnet", "nile"],
"scan_environment_kinds": ["mainnet"]
}
]
}GET /v1/networks/{slug}/credits
What an Address Watch event, a payment, a Tx Watch delivery and a block webhook cost in credits, per environment of the network.
Response fields
| Name | Type | Description |
|---|---|---|
| ok | boolean | true on success. |
| network_slug | string | Network slug. |
| network_name | string | Network display name. |
| environments[] | array | Active environments of the network. |
| environments[].slug | string | Environment slug (mainnet, sepolia, ...). |
| environments[].name | string | Environment display name. |
| environments[].kind | string | mainnet | testnet. |
| environments[].address_watch_credits | number | Credits for an Address Watch event (charged with the first event). |
| environments[].payment_credits | number | Credits for a payment (charged when the money is first seen). |
| environments[].block_credits | number | Credits for a block webhook (price of the get-block call). |
| environments[].tx_watch_credits | number | Credits for the final delivery of a Tx Watch hash. 0 means free. |
- Path parameter slug is the network slug (for example ethereum). An unknown or inactive network gives 404 with error_code network.not_found.
- Prices are per environment: a testnet usually costs less than its mainnet. kind is "mainnet" or "testnet".
- address_watch_credits is charged once, with the first event for a watched address; confirmations and the final state are free. payment_credits is charged once, when the money of a payment is first seen; the other payment events are free. tx_watch_credits is charged for the final delivery of a watched transaction (0 means free). block_credits is the price of one block webhook and equals the price of the network get-block call.
- Test webhooks are not charged.
Request example
import { createHash, createHmac } from 'node:crypto'
const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'
// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
const timestamp = Math.floor(Date.now() / 1000)
const bodyHash = createHash('sha256').update(body).digest('hex')
const signature = createHmac('sha256', SECRET)
.update([timestamp, method, path, bodyHash].join('\n'))
.digest('hex')
const res = await fetch(BASE + path, {
method,
headers: {
'X-Api-Key': API_KEY,
'X-Timestamp': String(timestamp),
'X-Signature': signature,
...(body ? { 'Content-Type': 'application/json' } : {}),
},
body: body || undefined,
})
return res.json()
}
console.log(await call('GET', '/api/public/v1/networks/SLUG/credits'))The request is signed in the snippet itself — see Authentication for the signing rules.
Response example
{
"ok": true,
"network_slug": "ethereum",
"network_name": "Ethereum",
"environments": [
{
"slug": "mainnet",
"name": "Mainnet",
"kind": "mainnet",
"address_watch_credits": 450,
"payment_credits": 750,
"block_credits": 40,
"tx_watch_credits": 150
},
{
"slug": "sepolia",
"name": "Sepolia Testnet",
"kind": "testnet",
"address_watch_credits": 225,
"payment_credits": 375,
"block_credits": 40,
"tx_watch_credits": 75
}
]
}GET /v1/networks/{slug}/methods
The RPC methods the network serves and what each costs in credits.
Response fields
| Name | Type | Description |
|---|---|---|
| ok | boolean | true on success. |
| network_slug | string | Network slug. |
| network_name | string | Network display name. |
| protocol | string | RPC family of the network. |
| methods[] | array | Active methods, ordered by sort. |
| methods[].uuid | string | Method uuid. |
| methods[].method | string | RPC method name, or the path for REST-style networks. |
| methods[].variant | string | Price variant of the method (default, full, ...). |
| methods[].credits | number | Credits per call. |
| methods[].http_methods | string[] | HTTP verbs the method is served with. |
| methods[].sort | number | Sort order. |
| methods[].description | string | Short description. Absent when none. (optional) |
- Path parameter slug is the network slug. An unknown or inactive network gives 404 with error_code network.not_found (ok: false, error_code, error).
- Only active methods are listed, ordered by sort. A method can appear several times with different variant values (for example "default" and "full", a cheaper and a heavier form of the same call); the price depends on the variant.
- protocol is the RPC family of the network (for example evm, solana, bitcoin, aptos, cosmos, other). For REST-style families method is a path such as /v1/accounts/{address}.
- http_methods tells which HTTP verbs the method is served with (POST for JSON-RPC, GET for REST).
- description is absent when the method has none.
Request example
import { createHash, createHmac } from 'node:crypto'
const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'
// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
const timestamp = Math.floor(Date.now() / 1000)
const bodyHash = createHash('sha256').update(body).digest('hex')
const signature = createHmac('sha256', SECRET)
.update([timestamp, method, path, bodyHash].join('\n'))
.digest('hex')
const res = await fetch(BASE + path, {
method,
headers: {
'X-Api-Key': API_KEY,
'X-Timestamp': String(timestamp),
'X-Signature': signature,
...(body ? { 'Content-Type': 'application/json' } : {}),
},
body: body || undefined,
})
return res.json()
}
console.log(await call('GET', '/api/public/v1/networks/SLUG/methods'))The request is signed in the snippet itself — see Authentication for the signing rules.
Response example
{
"ok": true,
"network_slug": "ethereum",
"network_name": "Ethereum",
"protocol": "evm",
"methods": [
{
"uuid": "b3a6c1de-7f10-4d0b-9e2a-1f4d8c5e6a70",
"method": "web3_clientVersion",
"variant": "default",
"credits": 5,
"http_methods": ["POST"],
"sort": 10,
"description": "Returns the current client version"
},
{
"uuid": "d41e9a02-3c58-4b6f-8a17-5e0c2b9f7d33",
"method": "eth_getBlockByNumber",
"variant": "full",
"credits": 40,
"http_methods": ["POST"],
"sort": 120
}
]
}GET /v1/network-status
Live status of all active networks: status, chain tip height and node latency, as last measured.
Response fields
| Name | Type | Description |
|---|---|---|
| ok | boolean | true on success. |
| checked_at | string | ISO-8601 time of this response. |
| networks[] | array | All active networks. |
| networks[].slug | string | Network slug. |
| networks[].name | string | Network display name. |
| networks[].status | string | ok | degraded | unknown | unsupported. |
| networks[].latency_ms | number | Answer time of the network in milliseconds. Absent when there is no value. (optional) |
| networks[].block_height | number | Last known chain tip. Absent when never measured. (optional) |
| networks[].environment_kinds | string[] | Slugs of all active environments of the network. |
| networks[].environment_kind | string | The environment the figures are of. Absent when the network has no active environment. (optional) |
| networks[].checked_at | string | ISO-8601 time of the last check of this network. |
- Takes no query parameters or body. It is cheap to poll.
- The figures are of one environment per network. environment_kind says which; environment_kinds lists all active environments.
- status is ok | degraded | unknown | unsupported. unknown means there is no recent status for the network; unsupported means status is not available for it.
- latency_ms, block_height and environment_kind are absent when there is no value (for example status unknown). checked_at on a network is the time of its last check; the top-level checked_at is the time of this response. Both are ISO-8601 UTC.
Request example
import { createHash, createHmac } from 'node:crypto'
const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'
// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
const timestamp = Math.floor(Date.now() / 1000)
const bodyHash = createHash('sha256').update(body).digest('hex')
const signature = createHmac('sha256', SECRET)
.update([timestamp, method, path, bodyHash].join('\n'))
.digest('hex')
const res = await fetch(BASE + path, {
method,
headers: {
'X-Api-Key': API_KEY,
'X-Timestamp': String(timestamp),
'X-Signature': signature,
...(body ? { 'Content-Type': 'application/json' } : {}),
},
body: body || undefined,
})
return res.json()
}
console.log(await call('GET', '/api/public/v1/network-status'))The request is signed in the snippet itself — see Authentication for the signing rules.
Response example
{
"ok": true,
"checked_at": "2026-08-07T12:00:30.512Z",
"networks": [
{
"slug": "ethereum",
"name": "Ethereum",
"status": "ok",
"latency_ms": 84,
"block_height": 23100456,
"environment_kinds": ["mainnet", "sepolia", "hoodi"],
"environment_kind": "mainnet",
"checked_at": "2026-08-07T12:00:02Z"
},
{
"slug": "tron",
"name": "TRON",
"status": "unknown",
"environment_kinds": ["mainnet", "nile"],
"environment_kind": "mainnet",
"checked_at": "2026-08-07T12:00:30.512Z"
}
]
}GET /v1/network-tokens
Tokens of a network that can be used for payments, by contract, with symbol and number of decimals.
Query parameters
| Name | Type | Description |
|---|---|---|
| network_slug | string | Network slug (for example ethereum). Required; up to 255 characters; case-insensitive. |
Response fields
| Name | Type | Description |
|---|---|---|
| ok | boolean | true on success. |
| items[] | array | Tokens of the network. Empty array when none. |
| items[].network_slug | string | Network slug. |
| items[].contract | string | Token contract address (token_contract in POST /v1/payments). |
| items[].symbol | string | Token symbol, for example USDT. |
| items[].decimals | number | Number of decimals of the token. |
- The coin of the network (ETH, TRX, BNB, ...) is not a token and is not in this list. A payment created without token_contract is made in the coin; a token payment names the token by its contract (see Payments).
- network_slug missing or empty gives 400 common.validation_failed with errors: [{ "field": "network_slug", "error": "network_slug is required." }]. A slug that matches no network gives an empty items array, not 404.
- Only tokens enabled for payments are listed, each once. A token that is switched off is not listed and a payment in it is rejected with network_token.disabled.
- Order: USDT, USDC, DAI and WETH first, then by symbol.
- decimals and symbol are fixed per token and cannot be set in a payment request. Use contract from this list as token_contract.
Request example
import { createHash, createHmac } from 'node:crypto'
const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'
// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
const timestamp = Math.floor(Date.now() / 1000)
const bodyHash = createHash('sha256').update(body).digest('hex')
const signature = createHmac('sha256', SECRET)
.update([timestamp, method, path, bodyHash].join('\n'))
.digest('hex')
const res = await fetch(BASE + path, {
method,
headers: {
'X-Api-Key': API_KEY,
'X-Timestamp': String(timestamp),
'X-Signature': signature,
...(body ? { 'Content-Type': 'application/json' } : {}),
},
body: body || undefined,
})
return res.json()
}
console.log(await call('GET', '/api/public/v1/network-tokens?network_slug=example'))The request is signed in the snippet itself — see Authentication for the signing rules.
Response example
{
"ok": true,
"items": [
{
"network_slug": "ethereum",
"contract": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"symbol": "USDT",
"decimals": 6
},
{
"network_slug": "ethereum",
"contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"symbol": "USDC",
"decimals": 6
}
]
}Tips
- Sign every request with X-Api-Key, X-Timestamp and X-Signature (see Authentication). Query strings such as ?network_slug=ethereum are part of the signed path.
- Errors use { ok: false, error_code, error } and, for a rejected request, an errors list naming each field. See Authentication for the auth errors.
- Network slugs and environment slugs from GET /v1/networks are the values you pass as network_slug and env_slug when creating RPC endpoints, watches and payments.
- Poll GET /v1/network-status for a status page or a pre-flight check instead of probing the nodes yourself. Remember the API limit of 100 requests per minute per account.