Quickstart
Call the JSON-RPC endpoint and the Data API with your API key.
This page shows the minimum you need to make your first authenticated call: how to get an
API key, how to call JSON-RPC with curl, and how to shape a Data API request. It reflects
the current behavior of rpc-gateway (data plane) and the planned behavior of the Data API
served by chain-indexer.
1. Get an API key
The console (self-service key management) has not shipped yet. Until it does, our operations team provisions accounts and keys manually. Go to Get an API key on the main site and we'll set you up.
Every key looks like rgw_ followed by 64 hex characters, for example
rgw_1f2e... (truncated). Keep it secret — anyone with the key can spend your balance.
2. Call JSON-RPC
All JSON-RPC traffic goes through a single gateway entry point, https://dev-api.blockvectra.network/v1/. There is no
WebSocket support and no CORS — the endpoint is meant to be called from a backend, not a
browser.
You can pass the key in one of two ways.
Key in the URL path
API_KEY="rgw_your_api_key"
curl -s "https://dev-api.blockvectra.network/v1/$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'Key in a request header
API_KEY="rgw_your_api_key"
curl -s "https://dev-api.blockvectra.network/v1/" \
-H 'Content-Type: application/json' \
-H "x-api-key: $API_KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'Don't drop the trailing slash
When you pass the key in a header, the path must be https://dev-api.blockvectra.network/v1/ with the trailing
slash. A request to the same URL without the trailing slash gets redirected (301) to the
version with the slash, and most HTTP clients turn the redirected request into a GET,
which then fails. Passing the key in the URL path does not have this problem.
An Authorization: Bearer <api_key> header also works and is used if x-api-key is absent
or empty. If both are present, a non-empty x-api-key wins.
Batch calls
Send an array to make several calls in one request (up to 100 per batch). This example reads the chain ID and an account balance in a single round trip:
curl -s "https://dev-api.blockvectra.network/v1/" \
-H 'Content-Type: application/json' \
-H "x-api-key: $API_KEY" \
-d '[
{"jsonrpc":"2.0","id":1,"method":"eth_chainId"},
{"jsonrpc":"2.0","id":2,"method":"eth_getBalance","params":["0x1111111111111111111111111111111111111111","latest"]}
]'Responses come back as an array, in the same order as the requests, matched by id.
3. Understand CU billing
Every billed call consumes Compute Units (CU): cheap calls like eth_blockNumber or
eth_chainId cost 1 CU, common reads like eth_getBlockByNumber cost a handful, heavier
calls like eth_call or eth_getLogs cost more, and debug_trace* calls cost the most.
Cached responses are always billed at 1 CU. Settlement is floor(total CU / 1000) billing
units per account per hour — the unit price itself is still being finalized by the business
side.
The full method-by-method weight table, cache behavior, and error codes live in API Reference → JSON-RPC once it ships — this page only covers the shape of a request.
Common errors
| What you did | What comes back |
|---|---|
| Missing, unknown, or disabled API key | HTTP 404 with an empty body (the gateway does not distinguish the reason) |
| Balance is zero or negative | HTTP 402, JSON-RPC code -32020 |
| Too many requests, or a single request exceeds your burst capacity | HTTP 429, JSON-RPC code -32005 |
A method that isn't allowed (e.g. eth_subscribe, or anything outside eth_*/net_*/web3_*/debug_trace*) | HTTP 200, JSON-RPC code -32601, not billed |
| Malformed JSON body | HTTP 200, JSON-RPC code -32700, not billed |
| More than 100 calls in one batch | HTTP 200, JSON-RPC code -32600 (batch too large), not billed |
Gateway-side rejections (all of the above) are never billed. Only calls the upstream node actually answers are billed.
4. Call the Data API
The Data API exposes read-only chain data (blocks, transactions, balances, holders, DEX
activity, and more) as REST/JSON. It's implemented by chain-indexer's serve-data process,
which today only listens on loopback (127.0.0.1:8546) — the public path prefix it will be
reachable under once rpc-gateway forwards to it has not been finalized yet. Always call
https://dev-api.blockvectra.network/v1 from your environment rather than hardcoding a host or a prefix; it will
resolve to the right thing once the forwarding ships.
The paths below (/blocks/{number}, /status/freshness, /addresses/{address}/balances)
are exactly what serve-data itself defines. Every success response uses the same envelope:
data (the payload), next_cursor (only present when there's another page — otherwise the
key is absent entirely, never null), and meta (as_of_block, finalized_block,
coverage, refreshed_at, rows_read when known, query_ms). Every error response is
{"error":{"code","message"}} — exactly those two fields, nothing else. Values that can
exceed 2^53 (balances, token amounts) are decimal strings, never JSON numbers.
Look up a block by number:
curl -s "https://dev-api.blockvectra.network/v1/blocks/72838701"{
"data": {
"number": 72838701,
"hash": "0x9f2c1e7a4b6d3f805e1c9a72b4d6f1e0a3c8b5d7e2f4a1c6b9d3e7f0a2c4b6d8",
"parent_hash": "0x1a3c5e7f9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a",
"timestamp": "2026-09-26T05:41:07Z",
"miner": "0x0000000000000000000000000000000000a4b05",
"gas_limit": 32000000,
"gas_used": 4821932,
"base_fee_per_gas": "100000000",
"state_root": "0x2b4d6f8a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d",
"transactions_root": "0x3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e",
"receipts_root": "0x4d6f8a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f",
"tx_count": 239,
"size": 48213,
"l1_block_number": null,
"extra": {}
},
"meta": {
"as_of_block": 72838957,
"finalized_block": 72838701,
"coverage": "full",
"refreshed_at": "2026-09-27T02:15:03Z",
"rows_read": 1,
"query_ms": 4
}
}A number with no live row (never indexed, or rolled back by a reorg) is 404
(error.code: "not_found"); a number above finalized_block is 409
(error.code: "finality_exceeded") — finality lags the indexed head by 256 blocks.
Check data freshness (how far every tracked table lags behind the chain head — useful for a status page or a pre-flight check before you trust a query):
curl -s "https://dev-api.blockvectra.network/v1/status/freshness"{
"data": [
{
"database": "robinhood",
"table_name": "blocks",
"category": "chain",
"key_kind": "block",
"max_block_number": 72838957,
"max_day": null,
"max_time": "2026-09-27T02:15:01Z",
"seconds_behind": 6,
"blocks_behind": 0,
"days_behind": null,
"rows_estimate": 72838958,
"bytes_estimate": 12345678901,
"follow_last_block": 72838957,
"follow_lag_blocks": 0,
"trace_min_block": null,
"trace_max_block": null,
"trace_gap_ranges": null,
"trace_gap_blocks": null,
"checked_at": "2026-09-27T02:15:07Z"
}
],
"meta": {
"as_of_block": 72838957,
"finalized_block": 72838701,
"coverage": "full",
"refreshed_at": "2026-09-27T02:15:07Z",
"query_ms": 412
}
}If the underlying data_freshness view isn't installed yet on a given environment, this
returns 422 (error.code: "dataset_not_installed") instead of a partial result.
List an address's ERC-20 balances (a snapshot refreshed every 6 hours, filtered to non-zero balances, ordered by token):
curl -s "https://dev-api.blockvectra.network/v1/addresses/0x1111111111111111111111111111111111111111/balances"{
"data": [
{ "token": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "balance": "500000000", "symbol": "WBTC", "decimals": 8 },
{ "token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "balance": "1250000000", "symbol": "USDC", "decimals": 6 }
],
"meta": {
"as_of_block": 72838957,
"finalized_block": 72838701,
"coverage": "full",
"refreshed_at": "2026-09-27T02:10:00Z",
"rows_read": 2,
"query_ms": 9
}
}An address with no non-zero balances still returns 200 with data: [] — never 404.
Pass ?limit= (default 50, max 500) and the returned next_cursor to page through more.
Full endpoint coverage — blocks, transactions, addresses, tokens, NFTs, DEX, tokenized stocks — will ship in API Reference → Data API, generated from the same pinned OpenAPI document these examples come from.
Where to next
- API Reference → JSON-RPC — methods, CU weights, error codes
- API Reference → Data API — REST endpoints for chain data
- API Reference → Console API — account, key, and usage management
- Datasets — the 27 derived datasets available on Robinhood Chain