---
title: "List supported chains"
method: GET
path: "/chains"
tags: ["Chain"]
---

# List supported chains

`GET /chains`

## Request

- Base URL: `https://api.blockvectra.com/v1/data`
- URL: `https://api.blockvectra.com/v1/data/chains`
- Auth: API key in header `x-api-key`

List the chains this API serves: their identifiers and display names, and for each chain what it serves (`features`, `subscriptions`, static capabilities), which blocks its data covers (`coverage`), the node's consensus `safe`/`finalized` markers and their status (`finality`) and its per-request caps (`limits`). Use an entry's `chain` value as the `{chain}` path parameter. A registered chain whose data store does not exist yet (not onboarded) is not listed and answers `404 not_found`; it appears once its data store is created.

## Response `200`

The chains this API serves. The example numbers are illustrative: `coverage.from_block` and `features` are live, read `GET /chains` at runtime.

- ChainsResponse
  - `build` Build, required: Opaque running release identities. indexer identifies the installed release; All component identities, including serve_data, come from the release manifest and change only when that component actually restarts. Missing or corrupt manifests yield five null values; missing component entries are null. No deployment metadata is exposed.
    - `indexer` string, nullable, required: First 12 lowercase hex digits of SHA-256 of full source commit + ":" + unique deployment identifier; never a commit prefix.
    - `follow` string, nullable, required: First 12 lowercase hex digits of SHA-256 of full source commit + ":" + unique deployment identifier; never a commit prefix.
    - `collect` string, nullable, required: First 12 lowercase hex digits of SHA-256 of full source commit + ":" + unique deployment identifier; never a commit prefix.
    - `serve_rpc` string, nullable, required: First 12 lowercase hex digits of SHA-256 of full source commit + ":" + unique deployment identifier; never a commit prefix.
    - `serve_data` string, nullable, required: First 12 lowercase hex digits of SHA-256 of full source commit + ":" + unique deployment identifier; never a commit prefix.
  - `data` Chain[], required
    - `chain` string, required: Chain identifier to call with: the value of the `{chain}` path parameter. Always the exact lowercase form of `chain_slug`.
    - `chain_slug` string, required: Canonical uppercase chain slug; a stable key for joining with other systems. `chain` is always its lowercase form.
    - `name` string, required: Human-readable display name for UIs. Not an identifier: do not use it as a key or in URLs.
    - `chain_id` integer, required: EIP-155 EVM chain ID.
    - `chain_external_id` string, required: CAIP-2 formatted external chain identifier (`eip155:{chain_id}`).
    - `status` 'ok' | 'syncing' | 'unavailable', required: Whether this chain is healthy and serving data (`ok`), syncing (`syncing`), or degraded/unavailable (`unavailable`). A chain is `syncing` when it has data and the data store is reachable, but `head_age_seconds` exceeds the per-chain threshold (default 300 seconds, configured via `[serve] syncing_after_seconds`).
    - `head_block` integer, nullable, required: The highest indexed block number, read live with the same TTL as coverage.has_data. During single timeouts or errors, retains the last known good block number within a 60-second window (HAS_DATA_MAX_STALE). null when no blocks have been indexed yet, head is unknown, or continuous failures exceed 60 seconds.
    - `head_age_seconds` integer, nullable, required: The age in integer seconds of the latest indexed block relative to current time, read live with the same TTL as coverage.has_data. During the 60-second failure window (HAS_DATA_MAX_STALE), continues to use the last known good head block and is always recalculated against the current clock (non-negative integer, clamped to 0 when the block timestamp is later than the current clock). null when no blocks have been indexed yet, head is unknown, or continuous failures exceed 60 seconds.
    - `features` string[], required: The capabilities this chain serves, in this order. An endpoint whose capability is not listed returns `422 no_coverage` on this chain (see Coverage in the API description).
    - `subscriptions` string[], required: The `eth_subscribe` kinds this chain declares it supports: a static capability from the chain registry's `[stream] subscriptions` (docs/design/0016 §8.6), not a live state. `[]` when the chain declares none -- WebSocket subscriptions are not served on it. The gateway offers a subscription only when it is both listed here and enabled for the chain on the gateway side.
    - `coverage` ChainCoverage, required: Which blocks this chain's data covers.
      - `from_block` integer, nullable, required: First block of the covered history: the lowest indexed block, read live (refreshed at most once a minute; `GET /chains` and the endpoints use the same value). `0` once the chain's history reaches genesis; higher while older blocks are still being imported or backfilled. It guarantees where coverage starts, not that every block above it is present. Block requests before it return `422 no_coverage` (when the block can be resolved), and `balances`, `holders` and `nfts`, which also need a contiguous history, are served only while it is `0` and the blocks have no hole. `null` while the chain has no indexed block at all (`has_data = false`; operations reaching their indexed-head check after passing earlier prerequisites answer `409 not_indexed_yet`), or while the floor cannot be determined (the data store is not answering and the last known value is more than 90 seconds old): it means **unknown** -- not complete history and not `0` -- so send no history requests for that chain; the endpoints that depend on the floor answer `503 unavailable` in the latter case. The property is always present. The example value is illustrative.
      - `traces_from_block` integer, nullable, required: First block with trace data, when `features` includes `traces`; `null` otherwise, or while there is no trace data yet, or while it cannot be determined (the trace endpoints answer `503` then). It is the boundary the trace endpoints apply (both are refreshed at most once a minute): trace requests before it, or inside a range the node could not trace, return `422 no_coverage`.
      - `has_data` boolean, nullable, required: Live: whether at least one block of this chain has been indexed. `false` is the explicit "no data yet" state (a node still syncing its first blocks): operations that pass their earlier routing, capability, parameter and permit checks and read the indexed head answer `409 not_indexed_yet` without `indexed_through` meanwhile. A missing capability still returns `422 no_coverage` before that head check. `true`: the chain serves data (how far behind it is comes from `status/freshness`). `null`: the data store could not answer, so unknown -- not "empty". A live read, refreshed at most every 5 seconds (every 2 seconds for `false` and `null`, so the switch to `true` after the first block shows up quickly); the query is bounded by a short timeout. During single timeouts or the data store errors, continues returning the last successful value within a 60-second bounded window (HAS_DATA_MAX_STALE); only turns null when continuous failures exceed 60 seconds or if this chain has never been successfully queried, never a failure of `GET /chains`.
    - `finality` ChainFinality, required: The chain's finality markers: the node's consensus `safe` and `finalized` blocks, the same values `meta.safe_block` / `meta.finalized_block` carry. Markers only -- they never bound a response (see Finality in the API description). The numbers are per chain and not comparable across chains.
      - `model` 'node_tags', required: Where the markers come from: the node's `safe` / `finalized` block tags.
      - `status` 'ok' | 'stale' | 'unavailable', required: `ok`: the indexer's heartbeat is at most 120 seconds old (it moves only with a successful read of the node's tags, so a null answer does not refresh it) and neither marker has stood still longer than the chain's configured stall threshold. `stale`: a value is known but the source is behind -- tag reads failing, a marker stalled (for example Ethereum not finalizing), or the markers table unreadable here; the blocks keep their last known values. `unavailable`: no value is known at all (the node has no such tags, or the first read has not happened, or this service never read one); both blocks are `null`.
      - `safe_block` integer, nullable, required: The node's `safe` block, `null` only when `status` is `unavailable`. Never below `finalized_block`.
      - `finalized_block` integer, nullable, required: The node's `finalized` block, `null` only when `status` is `unavailable`.
    - `limits` ChainLimits, required: Per-request caps and the query concurrency this service enforces on this chain.
      - `max_page_size` integer, required: Largest `limit`; larger values are clamped to it.
      - `max_window_blocks` integer, required: Widest `[from_block, to_block]` window of the windowed list endpoints (address transactions and transfers, DEX swaps by token).
      - `max_pools_for_token` integer, required: Most pools a `GET /{chain}/dex/swaps?token=` request may span.
      - `max_batch_addresses` integer, required: Most addresses one `POST /{chain}/tokens:batch` request may ask for.
      - `max_date_span_days` integer, required: Widest `from`..`to` date span of one `GET /{chain}/dex/prices` request, in days; a wider span is `409 span_exceeded`.
      - `max_concurrent_queries` integer, required: Requests of this chain the service answers at once. Point lookups (a block, a transaction, a token, an NFT, a stock, freshness) always keep one of them; list requests and trace requests share the rest, trace requests at most half of it. A request that finds none free waits a few seconds, then gets `503 unavailable` with `Retry-After`. Other chains have their own and are not affected.

## Other responses

- `401`: HTTP 401: a missing API key returns missing_api_key; an unknown, disabled, or revoked key returns the same invalid_api_key error envelope. error.code and error.data.reason contain the reason. Rejected requests are not billed.
- `402`: Payment required: the paid balance or the free grant is exhausted. The response body is `{"error":{"code":"insufficient_balance"}}`. Rejected requests are not billed.
- `429`: Rate limited. `{"error":{"code":"rate_limited"}}` when the key CU rate limit is exceeded (the response includes `Retry-After`) or the account call rate limit is exceeded (no `Retry-After`). `{"error":{"code":"cost_exceeds_burst"}}` when a single request exceeds the key burst capacity; split the request, retrying as sent never succeeds. Rejected requests are not billed.
- `503`: Temporarily unavailable; retry after the number of seconds in the `Retry-After` header. Body code `unavailable`, or `gateway_overloaded` (`Retry-After: 1`) when the account concurrency limit across all its keys and chains is reached or the service is temporarily busy. Reduce concurrent requests across the account and wait `Retry-After` before retrying. Rejected requests are not billed.

---

[API](https://skmtc.dev/blockvectra/apis/blockvectra-data-api.md) · [All operations](https://skmtc.dev/blockvectra/apis/blockvectra-data-api/llms.txt) · [OpenAPI document](https://skmtc.dev/blockvectra/apis/blockvectra-data-api/revisions/c5b949e955b5?raw)
