Every account has 1 reset chance (valid for 30 days) to refill up to 30,000,000 CU. Learn more →

Quickstart

Call the JSON-RPC endpoint and the Data API with your API key. Get a key, choose a chain, send a first request, and read the response and CU metering.

This page shows the minimum you need to make your first authenticated call: how to get an API key, how to choose a chain, how to call JSON-RPC, and how to shape a Data API request.

1. Get an API key

No API key yet?

If you do not have a BlockVectra API key: ask the user to sign in at console.blockvectra.com, create a key, and set it as the environment variable BLOCKVECTRA_API_KEY. Do not ask the user to paste the key into the chat.

Go to the console and log in with GitHub, Google or an Ethereum wallet (your account is created on first login). New accounts get 30,000,000 CU on sign-up — no credit card. Then create an API key. You can send a test request right in the console to check that it works. The secret is only displayed once upon creation, so store it securely right away. Creating, rotating or revoking a key takes a few seconds to take effect everywhere; if a brand-new key returns 404 right away, wait a moment and retry. For automated sign-up in an agent or CI environment without a browser, follow the Programmatic sign-up guide to sign up and create a key with a wallet signature.

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.

When your balance is insufficient, the gateway returns HTTP 402 (JSON-RPC error code -32020; Data API error.code insufficient_balance). Go to the console Billing page to check your balance and top-up methods.

Choose a chain

Every BlockVectra endpoint is scoped to a chain: JSON-RPC requests carry the chain name {chain} in the URL path, and Data API requests prefix the route with it. See Supported Chains for the chains currently available and their identifiers.

All examples on this page use robinhood_mainnet.

Tip: swap robinhood_mainnet in any example URL for any {chain} from Supported Chains to call that chain instead. The same API key works across all supported chains.

2. Call JSON-RPC

JSON-RPC endpoints are scoped to a chain: POST /v1/{chain}/{api_key} with the key in the path, or POST /v1/{chain} with the key in the x-api-key header. {chain} is the chain name the Data API also uses; for Robinhood Chain it is robinhood_mainnet, so the endpoint on this page is https://api.blockvectra.com/v1/robinhood_mainnet. The same API key works on every supported chain. There is no WebSocket support. The API sends Access-Control-Allow-Origin: *, but you should keep your API key secret and make requests from a backend service rather than client-side browser code.

You can pass the key in one of three ways: in the URL path (POST /v1/{chain}/{api_key}, which uses only the key in the path and ignores both headers), in the x-api-key header, or in an Authorization: Bearer <api_key> header.

Key in the URL path

export BLOCKVECTRA_API_KEY=rgw_your_api_key

curl -s "https://api.blockvectra.com/v1/robinhood_mainnet/$BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'

Key in a request header

export BLOCKVECTRA_API_KEY=rgw_your_api_key

curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" \
  -H 'Content-Type: application/json' \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'

No trailing slash

When you pass the key in a header, call https://api.blockvectra.com/v1/robinhood_mainnet exactly as shown: the URL ends with the chain name, without a trailing slash. JSON-RPC is served only at /v1/{chain} and /v1/{chain}/{api_key}. A trailing slash (like /v1/{chain}/) or a request without a chain segment (like /v1 or /v1/) returns 404 with an empty body. The legacy /v1/{api_key} returns 404 with an error.data.reason: "unknown_chain" error.

An Authorization: Bearer <api_key> header also works. On POST /v1/{chain}, a non-empty x-api-key takes precedence over Bearer, and Bearer is used only when x-api-key is absent or empty. The path form ignores both headers.

Batch calls

Send an array to make several calls in one request (up to 100 per batch). Note that each API key has a CU bucket (cu_per_sec refill, burst_cu capacity — defaults are 400 CU/s and burst 1,600 CU; shown per key in the console Keys table); a single request — including a whole JSON-RPC batch — whose total CU exceeds the key's burst capacity is rejected with -32022 request_exceeds_burst, even under the 100-calls-per-batch limit; split it into smaller batches. This example reads the chain ID and an account balance in a single round trip:

curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" \
  -H 'Content-Type: application/json' \
  -H "x-api-key: $BLOCKVECTRA_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.

If the gateway rejects the whole batch instead — insufficient balance, rate limiting, burst capacity, or more than 100 calls (see Common errors below) — it returns a single JSON-RPC error object instead of an array; viem's batch: true mode then surfaces this as an opaque UnknownRpcError, so retry a single call to see the actual error.

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. Usage is charged per account per hourly period, rounded down to whole billing units (1 unit = 1000 CU), with the remainder carrying over to the next period (so across periods the total charged is floor(total CU / 1000)); settlement runs about 15 minutes after the period ends. For example: 508 CU carried over + 2557 CU consumed = 3065 CU, resulting in 3 billing units charged and 65 CU carried over to the next period. See Pricing for current prices.

The full method-by-method weight table and error codes live in API Reference → JSON-RPC — this page only covers the shape of a request.

Common errors

What you didWhat comes backAction
Unknown or not yet public chain, or legacy /v1/{api_key}HTTP 404 with JSON body error.data.reason: "unknown_chain"Check the chain name in the URL
Request without a chain segment (e.g. /v1 or /v1/), or API key missing, unknown or disabledHTTP 404 with an empty bodyInclude the chain name in the URL (/v1/{chain}), or use a valid, active API key (brand-new or rotated keys take a few seconds to take effect; wait a moment and retry)
Balance is zero or negativeHTTP 402, JSON-RPC code -32020Top up your balance or wait for the free refill
Sent requests too quickly (rate limit or temporary overload)HTTP 429 (or 200), JSON-RPC code -32005Retry later (honour Retry-After when present)
Single request or batch exceeds key burst capacity (burst_cu, default 1,600 CU; default rate 400 CU/s), or free-plan batch exceeds calls/sec (25 calls/s)HTTP 429, JSON-RPC code -32022 (request_exceeds_burst)Split the request into smaller batches (can never succeed as sent, even under the 100-call limit)
Upstream node is temporarily unavailableHTTP 200, JSON-RPC code -32603 (upstream unavailable), not billedRetry the request
Historical state outside this chain's state window (Ethereum: about the last 250,000 blocks)HTTP 200, JSON-RPC code -32011, not billedQuery a more recent block
Transaction or block not found, or response too large; on Ethereum, block / receipt / log queries outside the recent window also return -32000 "old data not available due to pruning" (not billed; see Supported Chains → Ethereum)HTTP 200, JSON-RPC code -32000Change the request (verify hash or block number; malformed trace hashes return transaction not found)
Tracer not allowed, or trace timeout not allowed (debug_trace*)HTTP 200, JSON-RPC code -32602, not billedUse an allowed native tracer (callTracer, flatCallTracer, prestateTracer, 4byteTracer, noopTracer, or omit) and timeout ≤ 30s
A method the chain's method list does not allow (see Supported Chains)HTTP 200, JSON-RPC code -32601, not billedCall only methods the chain allows
Malformed JSON bodyHTTP 200, JSON-RPC code -32700, not billedFix request JSON syntax
More than 100 calls in one batchHTTP 200, JSON-RPC code -32600 (batch too large), not billedSplit the batch into at most 100 calls

The rejections above are never billed. Every accepted call that gets a response is charged at the method's published CU weight; the error-code table lists the cases that are not billed (see the Billed column in Error Codes). For debug_trace* calls, tracers must be built-in native tracers (callTracer, flatCallTracer, prestateTracer, 4byteTracer, noopTracer, or omitted) and timeouts must be ≤ 30s (-32602).

4. Call the Data API

The Data API exposes read-only chain data (blocks, transactions, balances, holders, DEX activity, and more) as REST/JSON. Every route except GET https://api.blockvectra.com/v1/data/chains is prefixed with a chain identifier: robinhood_mainnet is the chain identifier (the chain field returned by /chains and in meta) used in every path below. GET https://api.blockvectra.com/v1/data/chains lists only public chains and returns only {"data": [...]} (no meta, no next_cursor). Requests are metered and billed in Compute Units (CU); only 2xx successful responses are billed.

Every request requires the same API key as JSON-RPC — pass it in the x-api-key header. Every chain-scoped success response uses the same envelope: data (the payload), next_cursor (an opaque string, only present when there's another page — otherwise the key is absent entirely, never null), and meta (chain, chain_slug (upper-case form of chain), chain_external_id, as_of_block, finalized_block, coverage, refreshed_at; refreshed_at may be null, which means the update time of the data is unknown and it should be treated as stale — block-based endpoints always return a value). Error responses usually contain {"error":{"code","message"}} — 409 not_indexed_yet adds indexed_through (the highest indexed block). There are two exceptions for 404 errors: an unknown or not-public chain returns HTTP 404 with error.code not_found (decided before the key check, not billed, and not rate-limited; chain names must be exact lowercase slugs), while a missing, unknown, or disabled API key gets HTTP 404 with an empty body, as on JSON-RPC. Rate-limited requests return HTTP 429 (error.code rate_limited, data.reason: "key_rate_limit"), and exhausted balance returns HTTP 402 (error.code insufficient_balance); both are not billed. Values that can exceed 2^53 (balances, token amounts) are decimal strings, never JSON numbers.

Look up a block by number:

curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/blocks/72838701" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
{
  "data": {
    "number": 72838701,
    "hash": "0x9f2c1e7a4b6d3f805e1c9a72b4d6f1e0a3c8b5d7e2f4a1c6b9d3e7f0a2c4b6d8",
    "parent_hash": "0x1a3c5e7f9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a",
    "timestamp": "2026-09-26T05:41:07Z",
    "miner": "0x00000000000000000000000000000000000a4b05",
    "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": {
    "chain": "robinhood_mainnet",
    "chain_slug": "ROBINHOOD_MAINNET",
    "chain_external_id": "eip155:4663",
    "as_of_block": 72838957,
    "finalized_block": 72838701,
    "coverage": "full",
    "refreshed_at": "2026-09-27T02:15:03Z"
  }
}

A number above the indexed head (as_of_block) is 409 (error.code: "not_indexed_yet") with indexed_through telling you the highest indexed block — the data isn't there yet, so retry later. A number at or below as_of_block but above finalized_block is 409 (error.code: "finality_exceeded"). A number at or below finalized_block with no live row (never indexed, or rolled back by a reorg) is 404 (error.code: "not_found") — finality margin varies by chain; see Supported Chains.

Check data freshness (how far each tracked dataset lags behind the chain head — useful for a status page or a pre-flight check before you trust a query):

curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/status/freshness" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
{
  "data": [
    {
      "dataset": "blocks",
      "category": "raw",
      "max_block_number": 72838957,
      "max_day": null,
      "max_time": "2026-09-27T02:15:01Z",
      "seconds_behind": 0,
      "blocks_behind": 0,
      "days_behind": null,
      "checked_at": "2026-09-27T02:15:07Z"
    }
  ],
  "meta": {
    "chain": "robinhood_mainnet",
    "chain_slug": "ROBINHOOD_MAINNET",
    "chain_external_id": "eip155:4663",
    "as_of_block": 72838957,
    "finalized_block": 72838701,
    "coverage": "full",
    "refreshed_at": "2026-09-27T02:15:07Z"
  }
}

(Abridged: the response has one row per dataset; only the blocks row is shown. The traces row also carries coverage_from_block, coverage_to_block and coverage_complete.)

If freshness data is temporarily unavailable for this chain, this returns 503 (error.code: "unavailable") instead of a partial result; the response carries a Retry-After header (seconds) — wait at least that long, then retry.

List an address's ERC-20 balances (a snapshot refreshed every 6 hours, filtered to non-zero balances, ordered by token):

curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/balances" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
{
  "data": [
    { "token": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "balance": "500000000", "symbol": "WBTC", "decimals": 8 },
    { "token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "balance": "1250000000", "symbol": "USDC", "decimals": 6 }
  ],
  "meta": {
    "chain": "robinhood_mainnet",
    "chain_slug": "ROBINHOOD_MAINNET",
    "chain_external_id": "eip155:4663",
    "as_of_block": 72838957,
    "finalized_block": 72838701,
    "coverage": "full",
    "refreshed_at": "2026-09-27T02:10:00Z"
  }
}

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 — is available in API Reference → Data API.

Where to next

Migration note

BlockVectra is now multi-chain. Every chain-scoped JSON-RPC or Data API request includes the chain name {chain} in the URL (for example /v1/{chain}/{api_key} or /v1/data/{chain}/…). The legacy path /v1/{api_key} returns HTTP 404 with error.data.reason: "unknown_chain", while requests without a chain segment (such as /v1 or /v1/) return HTTP 404 with an empty body. The same API key works on every supported chain.

FAQ

Which chains are supported?

4 chains are supported: BNB Smart Chain, Ethereum, HyperEVM, Robinhood Chain. The list follows `GET /v1/chains` and updates when new chains launch. See the status page for live status. See supported chains →

Is WebSocket supported?

No. The API specification states there is no WebSocket support: eth_subscribe and eth_unsubscribe return -32601. To follow new events, poll eth_getLogs. See the eth_getLogs vs transfers guide →

Can I query historical state and traces?

Yes, but it varies by chain. The historical state window is the state_window_blocks field of /v1/chains (null means full history); whether traces are available depends on whether methods.allow for that chain includes debug_trace*; the maximum block span for a single eth_getLogs request is max_logs_block_range. See the chain directory and per-chain parameters →

Can one API key be used on all chains?

Yes. One API key works for JSON-RPC on every supported chain and for the Data API on chains that offer it; a key belongs to the account, not to a specific chain. Read the one key, many chains guide →

Last updated:

On this page