Guides

What is not billed: error codes and billing rules

A detailed breakdown of billing rules across HTTP status codes, JSON-RPC errors, and the Data API, with recommended actions for developers.

BlockVectra meters requests in Compute Units (CU). Calls are billed only after a response is obtained; units are not deducted when a request arrives. This guide summarizes the billing determination rules across HTTP status codes, JSON-RPC calls, and the Data API, along with recommended actions for developers.

HTTP Status Codes and Billing Rules

The billing determination and handling rules for HTTP-level responses are as follows:

HTTP StatusResponse BodyScenarioBilled?Recommended Action
200JSON-RPC response (single or batch)Normal response; all JSON-RPC layer errors (parse error, method rejection, guard, upstream failure, node error) are also 200Evaluated per callInspect result or error for each call; if an error is returned, see JSON-RPC error handling below
204EmptyAll calls in the request are notificationsNotifications are billed as normalNotifications are accepted and processed in the background; no extra action required
400EmptyMalformed HTTP message (cannot parse request line or headers, invalid chunked encoding), or more than 10 s between two reads of the request bodyNoCheck HTTP request syntax, headers, and transmission continuity
402JSON, -32020Insufficient balance, allowance exhausted (newly created keys return 503 rather than 402 before billing data is synchronized)NoGo to the Console billing page to check your balance and top up
403EmptyMethods other than POST or OPTIONS on /v1/{chain} or /v1/{chain}/{api_key} (regardless of whether chain name is known)NoChange the HTTP request method to POST (or cross-origin OPTIONS preflight)
404JSON, -32600 (reason = unknown_chain)POST to an unknown {chain} (request body not read, key not checked)NoCheck the chain name in the URL against Supported Chains (must be exact lowercase slug)
404empty bodyMissing key on known chain, key unknown or disabled; unmatched path (e.g. POST /v1, /v1/, POST /v1/{chain}/)NoInclude chain in URL (/v1/{chain}) or provide an active API key in x-api-key header (brand-new or rotated keys take a few seconds to take effect; wait a moment and retry)
408EmptyExceeded 35 s from reading request headers to returning responsePossible: calls already forwarded to the node are billed as normal once the node respondsDo not unconditionally retry state-changing calls (e.g. eth_sendRawTransaction); a client disconnect does not cancel calls already forwarded
413EmptyRequest body > 2 MiB (2,097,152 bytes), checked after auth and balance admissionNoKeep request body under 2 MiB; split batches into smaller requests
414 / 431EmptyURI too long (414) or request headers too large (431)NoShorten request URI or trim HTTP request headers
429JSON, -32005 or -32022; carries Retry-After when CU token bucket is depleted (-32005); account rate limit 429 does not carry itBucket balance depleted → -32005; single request CU exceeds burst capacity → -32022; account call rate limit depleted → -32005; calls in single request exceed limit → -32022NoFor -32005 with Retry-After, wait the specified seconds before retrying; for -32022, split the request or reduce batch size (retrying as-is will never succeed)
503JSON, -32021, with Retry-AfterBilling data temporarily unavailable; server temporarily rejects request (not a balance issue, no need to top up); newly created keys return this until billing data syncs (usually a few seconds)NoNot a balance issue, no need to top up; wait the seconds specified in Retry-After and retry

Note: When accessed through Cloudflare, Cloudflare may return 52x or 1015 error pages; these are not generated by the service.

JSON-RPC Error Codes and Billing Rules

The same error code can originate from the platform or the node, and billing differs:

  • Errors generated by the platform itself: never billed;
  • Errors returned by the node: passed through as-is and billed at the method weight, with only the node error codes listed below as exceptions.

Rule Details

  • Node errors not billed: The node's -32002 (batch timeout), -32003 (batch response too large), and -32600 (batch rejected as a whole) indicate that the node abandoned the call early and are not billed; notifications in the same batch are also not billed. 4444 indicates the requested block was pruned by the node (the node retains roughly 7 days of history), is not billed, and does not affect other calls in the batch. -32000 (only for historical state ... is not available, and Erigon's old data not available due to pruning...) indicates the request falls outside the node's state history window (roughly 128 blocks), is not billed, and does not affect other calls in the batch. Erigon has a window of about 36 days, is not billed, and does not affect other calls in the batch.
  • Node errors billed: Other errors returned by the node count as work done by the node and are billed at the method weight, such as execution reverted (-32000 or 3 with data), the node's own -32602 invalid argument, or -32601 returned for an eth_* method that passed platform admission but is not implemented by the node.
  • Balance admission and sync: -32020 indicates insufficient account balance and requires a top-up; -32021 indicates billing data is temporarily unavailable and the request is temporarily rejected—this is not a balance issue, no need to top up, simply wait the seconds specified in Retry-After and retry. A newly created key returns -32021 before the system reads billing data for its account (usually within a few seconds), not -32020; after reading, accounts with balance are accepted as normal, while accounts truly depleted or deleted receive -32020 (402).
  • Upstream failures: A -32603 generated by the platform due to upstream communication failure or malformed response (upstream unavailable, no response from upstream, malformed upstream response) carries data.reason: upstream_unavailable; internal gateway error is generated only in extremely rare cases of internal task panic or cancellation, does not represent upstream failure, and carries no data.reason.
  • Notification billing: Notifications (204) are billed as normal. Notifications are billed when the node processes the batch successfully: upstream HTTP 2xx; when the batch has calls with an id, at least one received a normal response and there are no -32002/-32003/-32600 elements; requests containing only notifications are billed if the upstream returns 2xx with an empty body.

JSON-RPC Error Codes Table

CodeSourceHTTPMessageReasonBilled?Recommended Action
-32700BlockVectra200parse error-No (costs 1 CU rate-limit token)Fix request JSON syntax
-32600BlockVectra200invalid requestinvalid_requestNo (costs 1 CU rate-limit token)Fix JSON-RPC request syntax and structure
-32600BlockVectra200batch too large: max <N> callsbatch_too_large (+max)NoSplit batch into calls under the limit (standard batch limit is 100)
-32600BlockVectra200invalid request: ambiguous member nameinvalid_requestNoRemove duplicate or ambiguous member names in JSON objects
-32601BlockVectra200method not available: <method>-NoCall only methods allowed for this chain (see Supported Chains)
-32600BlockVectra404unknown chainunknown_chainNoCheck the chain name in the URL
-32602BlockVectra200eth_getLogs block range too large: max <N> blocks-NoNarrow the eth_getLogs block range (limit defined per chain, e.g. 1000 blocks)
-32602BlockVectra200tracer not allowed-NoUse an allowed native tracer (callTracer, flatCallTracer, prestateTracer, 4byteTracer, noopTracer, or omit)
-32602BlockVectra200trace timeout not allowed-NoSet a valid Go duration string with timeout ≤ 30s
-32010BlockVectra200node is syncing; calls are temporarily unavailable-NoNode is syncing, retry later (except for eth_chainId)
-32011BlockVectra200historical state is not available beyond the most recent <N> blocks-NoQuery a more recent block (target block must be within the state window; avoid safe/finalized/earliest tags)
-32000BlockVectra200transaction not foundnot_foundNoVerify transaction hash (0x + 64 hex characters)
-32000BlockVectra200block not foundnot_foundNoVerify block hash or number
-32000BlockVectra200upstream response too largeresponse_too_largeNoNarrow query scope or split requests
-32005BlockVectra200gateway overloaded, retry lateroverloadedNoServer temporarily overloaded, retry later
-32005BlockVectra429rate limit exceededkey_rate_limit / free_plan_call_limit / concurrency_limitNoReduce request frequency; honour Retry-After when present
-32022BlockVectra429request cost <N> CU exceeds burst capacity <M> CUrequest_exceeds_burstNoSplit request or batch so single-request CU is below burst capacity
-32022BlockVectra429request has <N> calls, exceeding the free-plan limit of <M> calls per secondfree_plan_batch_too_large (+max)NoSplit batch to fit under per-second limit, or upgrade to a paid plan
-32603BlockVectra200upstream unavailableupstream_unavailableNoUpstream communication failure, retry later
-32603BlockVectra200no response from upstreamupstream_unavailableNoUpstream did not respond, retry later
-32603BlockVectra200malformed upstream responseupstream_unavailableNoUpstream response malformed, retry later
-32603BlockVectra200internal gateway error-NoRare internal error, retry later
-32020BlockVectra402insufficient balancebalance_exhausted / free_grant_exhaustedNoGo to Console billing page to top up, or wait for free refill
-32021BlockVectra503billing data temporarily unavailable-NoBilling data syncing (not a balance issue); wait Retry-After seconds and retry
4444Node200pruned history unavailable-NoRequested block was pruned by node (~7-day history retention); not billed; does not affect batch
-32000Node200historical state ... is not available-NoOutside node state history window (~128 blocks); not billed; does not affect batch
-32000Node200old data not available due to pruning...-No (Erigon, ETH mainnet)Outside node history window (Erigon ~36-day window); not billed; does not affect batch
-32002Node200<node message>-NoNode timed out on batch and abandoned call; not billed; notifications in batch also not billed
-32003Node200<node message>-NoNode batch response too large and abandoned; not billed; notifications in batch also not billed
-32600Node200<node message>-NoEntire batch rejected by node; not billed; notifications in batch also not billed
OtherNode200<node message>-Yes (method weight)Node performed work (e.g. execution reverted, node -32602, node -32601); check contract call parameters

Data API Billing Rules

The Data API wraps read-only chain data into REST endpoints. Its billing and error handling follow these rules:

Rule Details

  • "A Data API request is billed only when it succeeds."
  • "Requests are metered and billed in Compute Units (CU); only 2xx successful responses are billed."
  • "Chain-specific operations that are unavailable (e.g. unsupported chain or outside trace coverage) return HTTP 422 and are not billed."
  • "Requests outside our data coverage are not billed but may count toward rate limits."
  • "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 (identical to JSON-RPC). Requests exceeding rate limits return HTTP 429 (error.code rate_limited with data.reason key_rate_limit), and exhausted balances return HTTP 402 (error.code insufficient_balance); neither is billed."

Data API Status Codes Table

HTTP StatusError Code / ScenarioBilled?Recommended Action
200Successful data responseYes (Data API operation CU weight)Parse data, meta, and next_cursor in the response envelope
400Request parameters malformed or missing required fieldsNoCheck and fix query or body parameters
402Balance exhausted (error.code: "insufficient_balance")NoGo to Console billing page to check balance and top up
404Unknown or not-public chain (error.code: "not_found", decided before the key check; does not count against rate limits), requested object does not exist, or API key missing/unknown/disabled (empty body)NoCheck the chain slug in the URL (must be exact lowercase); pass a valid key in the x-api-key header
409Requested block is above the current indexed height (error.code: "not_indexed_yet", includes indexed_through)NoQuery blocks up to indexed_through or retry later
409Requested block is above finalized_block (error.code: "finality_exceeded")NoWait until the block is finalized, or query an older block
422Chain-specific operation unavailable (e.g. unsupported chain or outside trace coverage, error.code: "no_coverage")No (counts toward rate limits)Verify chain capabilities via GET https://dev-api.blockvectra.network/v1/data/chains to avoid queries outside coverage
429Rate limit exceeded (error.code: "rate_limited"), or a single request costs more than the key's burst capacity (error.code: "cost_exceeds_burst")NoReduce request frequency; split oversized requests (a burst-exceeding request will never succeed as sent)
503Data service temporarily unavailable (error.code: "unavailable"), or the chain is busy (error.code: "gateway_overloaded")NoRetry later and honour Retry-After when present

Testing note: These rules were confirmed on 2026-09-30 with a new free-plan account on the production environment: rejected methods (-32601), a syncing node (-32010), and the Data API's 409 finality_exceeded and 422 no_coverage did not add to usage, while successful calls were metered at the weights published by GET /v1/plans. This is a single observation, not a guarantee.

Pricing and Upgrades

The specific cost for all billed calls is determined by published CU weights:

  • To inspect weights for all methods and operations, see the method weight table and the JSON-RPC CU Metering Rules.
  • For plan pricing and settlement details, see the Pricing page.
  • Upgrading to a paid plan: making a paid top-up removes the Free Plan's per-second call limit; each key remains subject to CU rate and burst limits.

On this page