openapi: 3.1.0
info:
  title: BlockVectra Data API
  version: 0.1.0
  description: BlockVectra Data API — read-only REST endpoints over indexed data
    for each supported chain. The base URL is
    `https://dev-api.blockvectra.network/v1/data`; supply your API key in the
    `x-api-key` header.
  contact:
    name: BlockVectra
tags:
  - name: Chain
    description: Blocks and transactions.
  - name: Addresses
    description: Address-scoped transactions, transfers, and balances.
  - name: Tokens
    description: ERC-20/ERC-721/ERC-1155 transfers, holders, and metadata.
  - name: NFTs
    description: ERC-721/ERC-1155 ownership.
  - name: DEX
    description: DEX swaps and daily prices.
  - name: Stocks
    description: Tokenized-stock daily activity.
  - name: Traces
    description: Historical callTracer call trees.
  - name: Status
    description: Data freshness for each public dataset.
servers:
  - url: https://dev-api.blockvectra.network/v1/data
    description: BlockVectra Data API
security:
  - ApiKeyHeader: []
paths:
  /chains:
    get:
      tags:
        - Chain
      summary: List supported chains
      description: "List the chains this API serves: their identifiers and display
        names, and for each chain what it serves (`features`), which blocks its
        data covers (`coverage`), how its `finalized_block` is derived
        (`finality`) and its per-request caps (`limits`). Use an entry's `chain`
        value as the `{chain}` path parameter."
      operationId: getChains
      responses:
        "200":
          description: The chains this API serves (example `coverage.from_block` on window
            chains is illustrative; on window chains the start moves forward
            roughly weekly — read `GET /chains` `coverage.from_block` at
            runtime).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChainsResponse"
              example:
                data:
                  - chain: robinhood_mainnet
                    chain_slug: ROBINHOOD_MAINNET
                    name: Robinhood Chain
                    chain_id: 4663
                    chain_external_id: eip155:4663
                    features:
                      - blocks
                      - transactions
                      - address_transactions
                      - transfers
                      - token_metadata
                      - balances
                      - holders
                      - nfts
                      - dex_swaps
                      - dex_prices
                      - stocks
                      - traces
                      - freshness
                    coverage:
                      history_mode: full
                      from_block: 0
                      traces_from_block: 72050949
                    finality:
                      model: block_lag
                      lag_blocks: 256
                    limits:
                      max_page_size: 500
                      max_window_blocks: 100000
                      max_pools_for_token: 200
                      max_batch_addresses: 100
                      max_date_span_days: 90
                      max_concurrent_queries: 3
                  - chain: eth_mainnet
                    chain_slug: ETH_MAINNET
                    name: Ethereum
                    chain_id: 1
                    chain_external_id: eip155:1
                    features:
                      - blocks
                      - transactions
                      - address_transactions
                      - transfers
                      - token_metadata
                      - freshness
                    coverage:
                      history_mode: window
                      from_block: 26000000
                      retention_days: 30
                      traces_from_block: null
                    finality:
                      model: block_lag
                      lag_blocks: 64
                    limits:
                      max_page_size: 500
                      max_window_blocks: 100000
                      max_pools_for_token: 200
                      max_batch_addresses: 100
                      max_date_span_days: 90
                      max_concurrent_queries: 2
  /{chain}/status/freshness:
    get:
      tags:
        - Status
      summary: Freshness and lag per dataset
      description: Latest indexed block/day for each public dataset and how far it
        lags the chain head. Values may be up to 5 s old.
      operationId: getStatusFreshness
      parameters:
        - $ref: "#/components/parameters/ChainParam"
      responses:
        "200":
          description: One row per tracked dataset.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FreshnessEnvelope"
              example:
                data:
                  - dataset: blocks
                    category: raw
                    max_block_number: 72313256
                    max_day: null
                    max_time: 2026-09-28T03:41:07Z
                    seconds_behind: 0
                    blocks_behind: 0
                    days_behind: null
                    checked_at: 2026-09-28T03:41:10Z
                  - dataset: traces
                    category: raw
                    max_block_number: 72313256
                    max_day: null
                    max_time: 2026-09-28T03:41:07Z
                    seconds_behind: 0
                    blocks_behind: 0
                    days_behind: null
                    coverage_from_block: 72050949
                    coverage_to_block: 72313256
                    coverage_complete: true
                    checked_at: 2026-09-28T03:41:10Z
                  - dataset: dex_prices
                    category: derived
                    max_block_number: null
                    max_day: 2026-09-27
                    max_time: 2026-09-27T00:00:00Z
                    seconds_behind: 99667
                    blocks_behind: null
                    days_behind: 1
                    checked_at: 2026-09-28T03:41:10Z
                meta:
                  chain: robinhood_mainnet
                  chain_slug: ROBINHOOD_MAINNET
                  chain_external_id: eip155:4663
                  as_of_block: 72313256
                  finalized_block: 72313000
                  coverage: full
                  refreshed_at: 2026-09-28T03:41:10Z
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/blocks/{number}:
    get:
      tags:
        - Chain
      summary: Get a block by number
      description: Fetch a block by its block number. No pagination.
      operationId: getBlockByNumber
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/BlockNumberPath"
      responses:
        "200":
          description: The block.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BlockEnvelope"
        "400":
          description: '`error.code = "bad_request"`: `{number}` is not a valid
            non-negative integer.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or block `{number}` does not exist (never indexed, or
            removed by a reorg). A `{number}` above the indexed head is `409
            not_indexed_yet` instead.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "409":
          $ref: "#/components/responses/BlockAboveHead"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/blocks/hash/{hash}:
    get:
      tags:
        - Chain
      summary: Get a block by hash
      description: Fetch a block by its 32-byte block hash. Resolves the block hash to
        its height and returns the block record. Same response shape and
        finality rule as `GET /{chain}/blocks/{number}`. No pagination. On a
        `window` chain a hash that resolves to a block below
        `coverage.from_block` (the block has been dropped from the window) is
        `422 no_coverage`, not `404`.
      operationId: getBlockByHash
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/BlockHashPath"
      responses:
        "200":
          description: The block.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BlockEnvelope"
        "400":
          description: '`error.code = "bad_request"`: `{hash}` is not 32 bytes of hex (an
            optional `0x`/`0X` prefix is stripped first; either digit case is
            accepted).'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or no block with this `{hash}` exists. Hash lookups have no
            watermark to check "not indexed yet" against (unlike a block
            number), so `not_found` also covers the rare case of a just-mined
            block whose indexing is a few seconds behind; `message` says so --
            retry briefly before treating it as permanent.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                not_found:
                  value:
                    error:
                      code: not_found
                      message: block with hash '0xabcd...1234' not found (a just-mined block may take
                        a few seconds to be indexed)
        "409":
          $ref: "#/components/responses/FinalityExceeded"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/blocks/{number}/transactions:
    get:
      tags:
        - Chain
      summary: List a block's transactions
      description: "Keyset-paginated list of transactions in a block, ordered by
        `tx_index` ascending. A block with zero transactions returns `200` with
        `data: []`."
      operationId: getBlockTransactions
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/BlockNumberPath"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: This block's transactions, oldest `tx_index` first.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{number}`, invalid `limit`
            (`0`, negative, or non-integer — values above 500 are clamped, not
            rejected), or an invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or block `{number}` does not exist (never indexed, or
            removed by a reorg). A `{number}` above the indexed head is `409
            not_indexed_yet` instead.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "409":
          $ref: "#/components/responses/BlockAboveHead"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/transactions/{hash}:
    get:
      tags:
        - Chain
      summary: Get a transaction by hash
      description: Fetch a transaction by its 32-byte transaction hash. With
        `?include_logs=true`, receipt event logs for this transaction are
        included in the response. No pagination. On a `window` chain the hash of
        a transaction that has been dropped from the window is `404 not_found`
        (it cannot be told apart from a hash that never existed); a hash that
        still resolves to a block below `coverage.from_block` is `422
        no_coverage`.
      operationId: getTransactionByHash
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/TxHashPath"
        - name: include_logs
          in: query
          required: false
          description: "Strict boolean: absent defaults to `false`; the only accepted
            values are the literal strings `true` and `false` (any other value
            is `400 bad_request`, it does not silently fall back to `false`).
            When `true`, adds a `logs` array to `data`."
          schema:
            type: string
            enum:
              - "true"
              - "false"
      responses:
        "200":
          description: The transaction (with `logs` included when `?include_logs=true`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionPointEnvelope"
        "400":
          description: '`error.code = "bad_request"`: `{hash}` does not parse as a 32-byte
            hash (`0x` prefix optional, either digit case), or `include_logs` is
            present but is neither `true` nor `false`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or no transaction with this `{hash}` exists. Hash lookups
            have no watermark to check "not indexed yet" against (unlike a block
            number), so `not_found` also covers a transaction submitted moments
            ago whose indexing has not caught up yet; `message` says so -- retry
            briefly before treating it as permanent.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                not_found:
                  value:
                    error:
                      code: not_found
                      message: transaction 0x1234...abcd not found (a just-submitted transaction may
                        take a few seconds to be indexed)
        "409":
          description: '`error.code = "finality_exceeded"`: the block this transaction
            resolved to is above `finalized_block`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/addresses/{address}/transactions:
    get:
      tags:
        - Addresses
      summary: List an address's transactions
      description: >-
        Keyset-paginated list of transactions involving an address within a
        mandatory block window (`from_block` and `to_block` are both required).
        `direction=from` returns transactions sent by the address;
        `direction=to` returns transactions received by the address;
        `direction=any` (the default) merges both sent and received transactions
        ordered by `(block_number, tx_index)` descending, folding a
        self-transaction (`from == to == address`) into a single row. Opaque
        pagination token from the previous response's `next_cursor`; pass it
        back unchanged.


        **Window and finality clamping**: `to_block` above `finalized_block` is
        `409 finality_exceeded` unless `clamp=true`, which truncates `to_block`
        down to `finalized_block` (never possible when `from_block` is *itself*
        already past the watermark — that stays a hard 409 regardless of
        `clamp`). A window wider than 100,000 blocks is `409 window_too_large`
        unless `clamp=true`, which truncates from the older end (raises
        `from_block`, keeps `to_block` fixed). On a chain whose indexed history
        starts after genesis, a window entirely before its first indexed block
        is `422 no_coverage`; one that starts before it is partial, and
        `clamp=true` raises `from_block` to that block before the 100,000-block
        limit is applied. When clamped or partial, `meta.coverage = "partial"`
        (`"full"` otherwise).
      operationId: getAddressTransactions
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/AddressPath"
        - name: from_block
          in: query
          required: true
          description: Window lower bound (inclusive), non-negative integer. Required —
            there is no unwindowed query.
          schema:
            type: integer
            minimum: 0
        - name: to_block
          in: query
          required: true
          description: Window upper bound (inclusive), non-negative integer. Required.
            Must be `>= from_block`.
          schema:
            type: integer
            minimum: 0
        - name: direction
          in: query
          required: false
          description: Filter sent (`from`), received (`to`), or both (`any`). Defaults to
            `any`.
          schema:
            type: string
            enum:
              - from
              - to
              - any
            default: any
        - name: clamp
          in: query
          required: false
          description: When `true`, truncate an out-of-range window instead of failing
            with `409` (see above). Any value other than the literal string
            `true` is treated as `false`.
          schema:
            type: string
            default: "false"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: This address's transactions.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{address}`; missing
            `from_block`/`to_block`; either is not a non-negative integer;
            `from_block > to_block`; invalid `direction`; invalid `limit`; or an
            invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                invalid_cursor:
                  value:
                    error:
                      code: bad_request
                      message: invalid cursor
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: 'One of two codes: `error.code = "finality_exceeded"` when
            `to_block` (or, with `clamp=true`, `from_block` itself) is above
            `finalized_block` and there is nothing left to truncate to; or
            `error.code = "window_too_large"` when `[from_block, to_block]`
            spans more than 100,000 blocks and `clamp` was not `true`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                finality_exceeded:
                  value:
                    error:
                      code: finality_exceeded
                      message: requested window [100, 200] is above the finalized limit
                        (finalized_block=50); retry with a lower to_block or
                        clamp=true
                window_too_large:
                  value:
                    error:
                      code: window_too_large
                      message: window [0, 200000] spans 200001 blocks, exceeding the 100000-block
                        limit; retry with a narrower window or clamp=true
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/addresses/{address}/transfers:
    get:
      tags:
        - Addresses
      summary: List an address's token transfers
      description: >-
        Keyset-paginated list of token transfers involving an address within a
        mandatory block window (`from_block` and `to_block` are both required).
        Ordered by `(block_number, log_index)` descending.


        `direction=in|out|any` (defaults to `any`) filters by transfer direction
        relative to `{address}`. `token` optionally filters transfers for a
        specific token contract. `standard` must be `erc20` or `erc721`;
        `erc1155` returns `422 no_coverage`. Opaque pagination token from the
        previous response's `next_cursor`; pass it back unchanged.


        **Window and finality clamping**: `to_block` above `finalized_block` is
        `409 finality_exceeded` unless `clamp=true`, which truncates `to_block`
        down to `finalized_block` (never possible when `from_block` is *itself*
        already past the watermark — that stays a hard 409 regardless of
        `clamp`). A window wider than 100,000 blocks is `409 window_too_large`
        unless `clamp=true`, which truncates from the older end (raises
        `from_block`, keeps `to_block` fixed). On a chain whose indexed history
        starts after genesis, a window entirely before its first indexed block
        is `422 no_coverage`; one that starts before it is partial, and
        `clamp=true` raises `from_block` to that block before the 100,000-block
        limit is applied. When clamped or partial, `meta.coverage = "partial"`
        (`"full"` otherwise).
      operationId: getAddressTransfers
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/AddressPath"
        - name: standard
          in: query
          required: true
          description: Token standard to query. Must be one of `erc20`, `erc721`, or
            `erc1155`. Note that `erc1155` returns `422 no_coverage`.
          schema:
            type: string
            enum:
              - erc20
              - erc721
              - erc1155
        - name: token
          in: query
          required: false
          description: Optional token contract address filter.
          schema:
            $ref: "#/components/schemas/AddressInput"
        - name: from_block
          in: query
          required: true
          description: Window lower bound (inclusive), non-negative integer. Required —
            there is no unwindowed query.
          schema:
            type: integer
            minimum: 0
        - name: to_block
          in: query
          required: true
          description: Window upper bound (inclusive), non-negative integer. Required.
            Must be `>= from_block`.
          schema:
            type: integer
            minimum: 0
        - name: direction
          in: query
          required: false
          description: Filter incoming (`in`), outgoing (`out`), or both (`any`). Defaults
            to `any`.
          schema:
            type: string
            enum:
              - in
              - out
              - any
            default: any
        - name: clamp
          in: query
          required: false
          description: When `true`, truncate an out-of-range window instead of failing
            with `409`. Any value other than the literal string `true` is
            treated as `false`.
          schema:
            type: string
            default: "false"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: This address's token transfers.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddressTransferListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{address}`; missing or
            invalid `standard`; invalid `token`; missing
            `from_block`/`to_block`; either is not a non-negative integer;
            `from_block > to_block`; invalid `direction`; invalid `limit`; or an
            invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: 'One of two codes: `error.code = "finality_exceeded"` when
            `to_block` (or, with `clamp=true`, `from_block` itself) is above
            `finalized_block`; or `error.code = "window_too_large"` when
            `[from_block, to_block]` spans more than 100,000 blocks and `clamp`
            was not `true`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "422":
          description: "`error.code = \"no_coverage\"`: returned when `standard=erc1155`,
            as ERC-1155 transfers cannot be listed by address; when the chain
            does not have the `transfers` capability; or when the window is
            entirely before the chain's first indexed block (illustrative; on
            window chains the start moves forward roughly weekly — read `GET
            /chains` `coverage.from_block` at runtime)."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                erc1155:
                  value:
                    error:
                      code: no_coverage
                      message: ERC-1155 transfers cannot be listed by address; use GET
                        /{chain}/tokens/{token}/transfers?standard=erc1155
                        instead
                before_history:
                  summary: illustrative; on window chains the start moves forward roughly weekly —
                    read `GET /chains` `coverage.from_block` at runtime
                  value:
                    error:
                      code: no_coverage
                      message: window [25980000, 25999999] is before indexed history start 26000000 on
                        chain 'eth_mainnet'
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/tokens/{token}/transfers:
    get:
      tags:
        - Tokens
      summary: List a token contract's transfers
      description: Keyset-paginated list of token transfers for a specific token
        contract by `?standard=` (`erc20`, `erc721`, or `erc1155`), ordered by
        recency descending.
      operationId: getTokenTransfers
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/TokenPath"
        - name: standard
          in: query
          required: true
          description: Transfer standard to query (`erc20`, `erc721`, or `erc1155`).
          schema:
            type: string
            enum:
              - erc20
              - erc721
              - erc1155
        - name: from_block
          in: query
          required: false
          description: Optional lower bound (inclusive), non-negative integer.
          schema:
            type: integer
            minimum: 0
        - name: to_block
          in: query
          required: false
          description: Optional upper bound (inclusive), non-negative integer. Absent
            defaults to `finalized_block` (never an error); an explicit value
            above `finalized_block` is a hard `409` — there is no `clamp` escape
            for this endpoint.
          schema:
            type: integer
            minimum: 0
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: This token's transfers, newest first.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenTransferListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{token}`; missing
            `standard`; `standard` not one of `erc20`/`erc721`/`erc1155`;
            `from_block`/`to_block` not a non-negative integer; `from_block >
            to_block`; invalid `limit`; or an invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: '`error.code = "finality_exceeded"`: an explicit `to_block` is
            above `finalized_block`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/addresses/{address}/balances:
    get:
      tags:
        - Addresses
      summary: List an address's ERC-20 balances
      description: "Keyset-paginated list of non-zero ERC-20 balances for an address,
        ordered by `token` address ascending. Token metadata (`symbol`,
        `decimals`) is included where available. An address with no balances
        returns `200` with `data: []`."
      operationId: getAddressBalances
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/AddressPath"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: This address's non-zero ERC-20 balances, `token` ascending.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddressBalanceListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{address}`; invalid
            `limit`; or an invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/tokens/{token}/holders:
    get:
      tags:
        - Tokens
      summary: List a token's holders
      description: 'Keyset-paginated list of token holders for an ERC-20 token,
        ordered by `balance DESC, holder DESC`. `meta.coverage` is always
        `"full"`: a truncated page simply carries a `next_cursor`.'
      operationId: getTokenHolders
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/TokenPath"
        - $ref: "#/components/parameters/Limit"
        - name: sort
          in: query
          required: false
          description: "Sort order. Supported values: `balance`. Omitting it also sorts by
            balance."
          schema:
            type: string
            enum:
              - balance
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: This token's holders, largest balance first.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenHolderListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{token}`; `sort` present
            and not `balance`; invalid `limit`; or an invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              example:
                error:
                  code: bad_request
                  message: "invalid sort 'foo': supported values: balance"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/tokens/{token}:
    get:
      tags:
        - Tokens
      summary: Get token metadata
      description: Fetch token metadata (symbol, name, decimals, total supply) by
        contract address.
      operationId: getTokenMeta
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/TokenPath"
      responses:
        "200":
          description: Token metadata.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{token}`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or metadata for `{token}` was not found.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/tokens:batch:
    post:
      tags:
        - Tokens
      summary: Batch get token metadata
      description: Batch retrieve token metadata for up to 100 addresses. Unknown
        addresses do not trigger an error; they are listed in `missing` instead.
        Duplicate addresses in the request are deduplicated in both `tokens` and
        `missing`, each in first-occurrence request order.
      operationId: postTokensBatch
      parameters:
        - $ref: "#/components/parameters/ChainParam"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TokensBatchRequest"
            example:
              addresses:
                - "0x1111111111111111111111111111111111111111"
                - "0x2222222222222222222222222222222222222222"
      responses:
        "200":
          description: Found tokens plus the list of addresses that were not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokensBatchEnvelope"
        "400":
          description: '`error.code = "bad_request"`: the body is not valid JSON matching
            `{"addresses": [...]}`; `addresses` has more than 100 entries; or
            any entry is not a valid 20-byte address (the request fails on the
            first invalid address it walks to, not a batched report of every
            invalid one).'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                invalid_json:
                  value:
                    error:
                      code: bad_request
                      message: request body is not valid JSON (line 1, column 4)
                missing_addresses:
                  value:
                    error:
                      code: bad_request
                      message: missing required field `addresses`
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/nfts/{contract}/{token_id}:
    get:
      tags:
        - NFTs
      summary: Get one NFT's owner/holders
      description: Get ownership for a specific NFT token ID by contract address.
        Returns the ERC-721 owner or the list of ERC-1155 token holders.
      operationId: getNftByContractAndTokenId
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - name: contract
          in: path
          required: true
          description: 20-byte contract address, `0x` optional, either case.
          schema:
            $ref: "#/components/schemas/AddressInput"
        - name: token_id
          in: path
          required: true
          description: Decimal (base-10) integer string, must fit in `UInt256`. Empty,
            non-decimal, or out-of-range values are `400`.
          schema:
            type: string
            pattern: ^[0-9]+$
      responses:
        "200":
          description: The ERC-721 owner or ERC-1155 holder list for this `(contract,
            token_id)`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NftPointEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{contract}`, or
            `{token_id}` is not a plain non-negative decimal integer (or does
            not fit in `UInt256`).'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or no ownership record was found for this `(contract,
            token_id)`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/nfts:
    get:
      tags:
        - NFTs
      summary: List NFTs owned by an address
      description: Keyset-paginated list of NFTs owned by an address (ERC-721 holdings
        followed by ERC-1155 holdings), optionally filtered by contract address.
        Opaque pagination token from the previous response's `next_cursor`; pass
        it back unchanged. A page may hold fewer than `limit` items, or none,
        while `next_cursor` is present; keep following `next_cursor` until it is
        absent.
      operationId: getNftsByOwner
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - name: owner
          in: query
          required: true
          description: 20-byte owner/holder address, `0x` optional, either case.
          schema:
            $ref: "#/components/schemas/AddressInput"
        - name: contract
          in: query
          required: false
          description: Optional 20-byte contract address to restrict the list to a single
            collection.
          schema:
            $ref: "#/components/schemas/AddressInput"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: NFTs owned by `owner` (ERC-721 entries before ERC-1155 entries).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NftListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: missing `owner`; invalid
            `owner`/`contract`; invalid `limit`; or an invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/dex/swaps:
    get:
      tags:
        - DEX
      summary: List DEX swaps by pool or token
      description: Keyset-paginated list of DEX swaps, queried by pool or by token
        contract. Exactly one of `pool` or `token` must be specified. For
        `token`, a block window is mandatory (`from_block` and `to_block` are
        both required, spanning at most 100,000 blocks). The parameter `trader`
        is not supported and will return `400 bad_request`.
      operationId: getDexSwaps
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - name: pool
          in: query
          required: false
          description: Exactly one of `pool`/`token` is required. Accepts either a 20-byte
            pool address (left-zero-padded to 32 bytes, Uniswap V2/V3
            convention) or a 32-byte pool key (Uniswap V4 `poolId`); `0x`
            optional, either case.
          schema:
            type: string
        - name: token
          in: query
          required: false
          description: Exactly one of `pool`/`token` is required. 20-byte token address,
            `0x` optional, either case.
          schema:
            $ref: "#/components/schemas/AddressInput"
        - name: trader
          in: query
          required: false
          description: The 'trader' parameter is not supported; filter by 'pool' or
            'token' instead.
          schema:
            type: string
        - name: from_block
          in: query
          required: false
          description: Lower bound (inclusive). Optional for `pool`; **required** for
            `token`.
          schema:
            type: integer
            minimum: 0
        - name: to_block
          in: query
          required: false
          description: Upper bound (inclusive). Optional for `pool` (defaults to
            `finalized_block`); **required** for `token`. An explicit value
            above `finalized_block` is `409 finality_exceeded`.
          schema:
            type: integer
            minimum: 0
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: Matching swaps, newest first.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DexSwapListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: `trader` present; neither or both of
            `pool`/`token` given; malformed `pool`/`token`; `token` filter
            missing `from_block`/`to_block`; `from_block > to_block`; invalid
            `limit`; or an invalid `cursor`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              example:
                error:
                  code: bad_request
                  message: the 'trader' parameter is not supported; filter by 'pool' or 'token'
                    instead
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: 'One of three codes: `error.code = "finality_exceeded"` (window
            above `finalized_block`); `error.code = "window_too_large"` (`token`
            dimension window spans more than 100,000 blocks); or `error.code =
            "too_many_pools"` (`token` matches more than 200 pools — retry with
            the `pool` dimension instead).'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                too_many_pools:
                  value:
                    error:
                      code: too_many_pools
                      message: token matches 214 pools, exceeding limit of 200; query by pool
                        dimension instead
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/dex/prices:
    get:
      tags:
        - DEX
      summary: Daily DEX token prices
      description: "Daily volume-weighted average price (VWAP) and volume for a DEX
        token over a specified date range (up to 90 days). Not paginated:
        `next_cursor` is never present."
      operationId: getDexPrices
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - name: token
          in: query
          required: true
          description: 20-byte base token address, `0x` optional, either case.
          schema:
            $ref: "#/components/schemas/AddressInput"
        - name: quote
          in: query
          required: false
          description: Optional 20-byte quote token address to restrict to a single
            base/quote pair.
          schema:
            $ref: "#/components/schemas/AddressInput"
        - name: from
          in: query
          required: true
          description: UTC start date, inclusive, `YYYY-MM-DD`.
          schema:
            type: string
            format: date
        - name: to
          in: query
          required: true
          description: UTC end date, inclusive, `YYYY-MM-DD`. `to - from` must be `<= 90`
            days.
          schema:
            type: string
            format: date
      responses:
        "200":
          description: Daily price/volume rows for `[from, to]` (empty array if none).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DexPriceListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: missing `token`/`from`/`to`; invalid
            `token`/`quote`; `from`/`to` not a valid `YYYY-MM-DD` calendar date;
            or `from` after `to`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: '`error.code = "span_exceeded"`: `to - from` is more than 90 days.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              example:
                error:
                  code: span_exceeded
                  message: date span from 2026-01-01 to 2026-12-31 is 364 days, exceeding the
                    90-day limit
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/stocks:
    get:
      tags:
        - Stocks
      summary: Daily leaderboard of tokenized stocks
      description: Daily leaderboard of tokenized stock activity for a specified UTC
        date, including display metadata (symbol, name, currency, CUSIP, market
        identifier) ordered by transfer activity descending. Not paginated
        (`limit` caps the page).
      operationId: getStocks
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - name: day
          in: query
          required: false
          description: "UTC day, `YYYY-MM-DD`. Absent defaults to the latest recorded day
            (if no activity is recorded, returns `200` with `data: []`)."
          schema:
            type: string
            format: date
        - $ref: "#/components/parameters/Limit"
      responses:
        "200":
          description: Stock tokens active on `day`, most active first.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StockDailyListEnvelope"
        "400":
          description: '`error.code = "bad_request"`: `day` present but not a valid
            `YYYY-MM-DD` calendar date, or invalid `limit`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/stocks/{token}:
    get:
      tags:
        - Stocks
      summary: Get one tokenized stock
      description: Fetch tokenized stock metadata and up to 30 days of recent daily
        metrics by token address.
      operationId: getStockByToken
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/TokenPath"
      responses:
        "200":
          description: This stock token's metadata plus its recent daily metrics.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StockTokenEnvelope"
        "400":
          description: '`error.code = "bad_request"`: invalid `{token}`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or `{token}` is not a known tokenized stock.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "422":
          $ref: "#/components/responses/NoCoverage"
        "503":
          $ref: "#/components/responses/Unavailable"
  /{chain}/blocks/{number}/traces:
    get:
      tags:
        - Traces
      summary: Historical callTracer trace tree for a whole block
      description: Reconstructed call tree per transaction in a block using
        `callTracer`, wrapped in the standard response envelope. **Returns the
        whole block, unpaginated** (`next_cursor` is never present). A permanent
        coverage gap returns `422`, never an empty array; a recent block with
        transactions but no trace data yet returns `503` instead -- once it is
        further behind the indexed head than the chain's trace window, it is
        `422` too (see "Errors" above).
      operationId: getBlockTraces
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/BlockNumberPath"
      responses:
        "200":
          description: One call tree per transaction in the block, in `tx_index` order
            (`[]` for a real, finalized block that has zero transactions).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BlockTracesEnvelope"
        "400":
          description: '`error.code = "bad_request"`: `{number}` is not a valid
            non-negative integer.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or block `{number}` does not exist (never indexed, or
            removed by a reorg).'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "409":
          $ref: "#/components/responses/BlockAboveHead"
        "422":
          description: "`error.code = \"no_coverage\"`: the chain does not have the
            `traces` capability (checked first), or `{number}` falls in a
            permanent trace coverage gap -- the chain has no trace data at all
            yet (`coverage.traces_from_block` is `null`), `{number}` is before
            trace coverage started (below the chain's
            `coverage.traces_from_block` in `GET /chains`), inside a recorded
            gap, or (distinct from the `503` case below) it has transactions but
            was never traced and is already too far behind the indexed head for
            that to still be a pending write. `message` names the chain and the
            reason."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                capability:
                  value:
                    error:
                      code: no_coverage
                      message: chain 'eth_mainnet' does not support traces
                no_trace_data:
                  value:
                    error:
                      code: no_coverage
                      message: "block 12345 has no trace coverage on chain 'robinhood_mainnet': no
                        trace data available"
                before_coverage_start:
                  value:
                    error:
                      code: no_coverage
                      message: "block 12345 has no trace coverage on chain 'robinhood_mainnet':
                        coverage starts at block 72050949"
                coverage_gap:
                  value:
                    error:
                      code: no_coverage
                      message: "block 73467699 has no trace coverage on chain 'robinhood_mainnet':
                        trace data is not available for blocks
                        73467692-73467699"
                permanent_hole:
                  value:
                    error:
                      code: no_coverage
                      message: "block 71993211 has no trace coverage on chain 'robinhood_mainnet':
                        trace data is not available"
        "503":
          description: "`error.code = \"unavailable\"`: the data store is unreachable or
            slow (including while the chain's trace coverage start cannot be
            determined), or (see \"Errors\" above) `{number}` is a recent block
            with transactions but no trace data yet -- always with
            `Retry-After`."
          headers:
            Retry-After:
              required: true
              schema:
                type: integer
                minimum: 1
              description: Seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              example:
                error:
                  code: unavailable
                  message: trace data for this block is not written yet; retry shortly
  /{chain}/transactions/{hash}/trace:
    get:
      tags:
        - Traces
      summary: Historical callTracer trace tree for one transaction
      description: Reconstructed `callTracer` call frame for a single transaction by
        its transaction hash. Unpaginated; `next_cursor` is never present.
        `data` is the call frame object directly.
      operationId: getTransactionTrace
      parameters:
        - $ref: "#/components/parameters/ChainParam"
        - $ref: "#/components/parameters/TxHashPath"
      responses:
        "200":
          description: This transaction's call tree.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TxTraceEnvelope"
        "400":
          description: '`error.code = "bad_request"`: `{hash}` does not parse as a 32-byte
            hash (`0x` optional, either case).'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "404":
          description: '`error.code = "not_found"`: either `{chain}` is unknown or not
            public, or no transaction with this `{hash}` exists, or it resolved
            to a block whose trace tree has no matching transaction. Hash
            lookups have no watermark to check "not indexed yet" against, so
            `not_found` also covers a transaction submitted moments ago whose
            indexing has not caught up yet; `message` says so -- retry briefly
            before treating it as permanent.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                not_found:
                  value:
                    error:
                      code: not_found
                      message: transaction 0x1234...abcd not found (a just-submitted transaction may
                        take a few seconds to be indexed)
        "409":
          description: '`error.code = "finality_exceeded"`: the resolved block is above
            `finalized_block`.'
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
        "422":
          description: "`error.code = \"no_coverage\"`: the chain does not have the
            `traces` capability (checked first), or the resolved block falls in
            a permanent trace coverage gap -- the chain has no trace data at all
            yet (`coverage.traces_from_block` is `null`), the block is before
            trace coverage started (below the chain's
            `coverage.traces_from_block` in `GET /chains`), inside a recorded
            gap, or (distinct from the `503` case below) it has transactions but
            was never traced and is already too far behind the indexed head for
            that to still be a pending write. `message` names the chain and the
            reason."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              examples:
                capability:
                  value:
                    error:
                      code: no_coverage
                      message: chain 'eth_mainnet' does not support traces
                no_trace_data:
                  value:
                    error:
                      code: no_coverage
                      message: "block 12345 has no trace coverage on chain 'robinhood_mainnet': no
                        trace data available"
                before_coverage_start:
                  value:
                    error:
                      code: no_coverage
                      message: "block 12345 has no trace coverage on chain 'robinhood_mainnet':
                        coverage starts at block 72050949"
                coverage_gap:
                  value:
                    error:
                      code: no_coverage
                      message: "block 73467699 has no trace coverage on chain 'robinhood_mainnet':
                        trace data is not available for blocks
                        73467692-73467699"
                permanent_hole:
                  value:
                    error:
                      code: no_coverage
                      message: "block 71993211 has no trace coverage on chain 'robinhood_mainnet':
                        trace data is not available"
        "503":
          description: "`error.code = \"unavailable\"`: the data store is unreachable or
            slow (including while the chain's trace coverage start cannot be
            determined), or (see \"Errors\" above) the resolved block is a
            recent block with transactions but no trace data yet -- always with
            `Retry-After`."
          headers:
            Retry-After:
              required: true
              schema:
                type: integer
                minimum: 1
              description: Seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorBody"
              example:
                error:
                  code: unavailable
                  message: trace data for this block is not written yet; retry shortly
components:
  parameters:
    ChainParam:
      name: chain
      in: path
      required: true
      description: "Chain identifier: the `chain` value of an entry in `GET /chains`
        (for example `robinhood_mainnet`), which lists every value this API
        accepts, i.e. the exact lowercase form of that entry's `chain_slug`.
        Matching is exact and case-sensitive; other spellings, aliases and
        numeric chain IDs are not accepted and return `404 not_found` (unknown
        or not-public chain). What the chain serves differs per chain: see that
        entry's `features` and `coverage`."
      schema:
        type: string
        pattern: ^[a-z][a-z0-9]*(_[a-z0-9]+)+$
      examples:
        robinhood_mainnet:
          value: robinhood_mainnet
        eth_mainnet:
          value: eth_mainnet
    BlockNumberPath:
      name: number
      in: path
      required: true
      description: Non-negative block height.
      schema:
        type: integer
        format: int64
        minimum: 0
    BlockHashPath:
      name: hash
      in: path
      required: true
      description: 32-byte block hash, `0x`/`0X` prefix optional, either digit case.
      schema:
        $ref: "#/components/schemas/HashInput"
    TxHashPath:
      name: hash
      in: path
      required: true
      description: 32-byte transaction hash, `0x` prefix optional, either digit case.
      schema:
        $ref: "#/components/schemas/HashInput"
    AddressPath:
      name: address
      in: path
      required: true
      description: 20-byte address, `0x` optional, either case.
      schema:
        $ref: "#/components/schemas/AddressInput"
    TokenPath:
      name: token
      in: path
      required: true
      description: 20-byte token contract address, `0x` optional, either case.
      schema:
        $ref: "#/components/schemas/AddressInput"
    Limit:
      name: limit
      in: query
      required: false
      description: Page size. Absent defaults to 50. `0` or a non-integer value is
        `400 bad_request`. A value above 500 is clamped to 500, not rejected.
      schema:
        type: integer
        minimum: 1
        default: 50
        maximum: 500
    Cursor:
      name: cursor
      in: query
      required: false
      description: Opaque pagination token from the previous response's `next_cursor`;
        pass it back unchanged.
      schema:
        type: string
  responses:
    BadRequest:
      description: '`error.code = "bad_request"`: duplicate query parameter, invalid
        query string, or malformed request.'
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorBody"
          examples:
            duplicate_parameter:
              value:
                error:
                  code: bad_request
                  message: query parameter 'limit' may be given only once
            invalid_query_string:
              value:
                error:
                  code: bad_request
                  message: invalid query string
    NotFound:
      description: '`error.code = "not_found"`: the target object was not found, or
        `{chain}` is not a registered or public chain (returns HTTP 404 with
        `error.code = "not_found"`, not billed). Missing, unknown, or disabled
        API keys return 404 with an empty body.'
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorBody"
          examples:
            unknown_chain:
              summary: Unknown or not-public chain
              value:
                error:
                  code: not_found
                  message: unknown chain
            object_not_found:
              summary: Resource not found
              value:
                error:
                  code: not_found
                  message: block not found
          example:
            error:
              code: not_found
              message: unknown chain
    NoCoverage:
      description: "`error.code = \"no_coverage\"`: permanently no data here. Either
        the chain does not have this endpoint's capability, or the requested
        block (or whole block window) is before the chain's first covered block
        (`coverage.from_block`, which moves forward on a `window` chain), or
        (traces) the block falls in a permanent trace coverage gap. A block
        window entirely before the first indexed block is reported as this `422`
        even when its `to_block` is also above `finalized_block`. See Coverage
        in the API description (the history start in examples is illustrative;
        on window chains the start moves forward roughly weekly — read `GET
        /chains` `coverage.from_block` at runtime)."
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorBody"
          examples:
            capability:
              value:
                error:
                  code: no_coverage
                  message: chain 'eth_mainnet' does not support balances
            before_history:
              summary: illustrative; on window chains the start moves forward roughly weekly —
                read `GET /chains` `coverage.from_block` at runtime
              value:
                error:
                  code: no_coverage
                  message: block 1 is before indexed history start 26000000 on chain 'eth_mainnet'
    Unavailable:
      description: '`error.code = "unavailable"`: the service is temporarily
        unavailable, timed out, busy on this chain (no query slot freed up in
        time, see `limits.max_concurrent_queries` in `GET /chains`), or shutting
        down (see "Errors" above). Always carries an HTTP `Retry-After` header
        (seconds); wait at least that long before retrying.'
      headers:
        Retry-After:
          required: true
          schema:
            type: integer
            minimum: 1
          description: Seconds to wait before retrying.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorBody"
          example:
            error:
              code: unavailable
              message: service temporarily unavailable, please retry
    FinalityExceeded:
      description: '`error.code = "finality_exceeded"`: the requested block is indexed
        but above `finalized_block` (not yet reorg-safe).'
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorBody"
          example:
            error:
              code: finality_exceeded
              message: block 999999999 is above the finalized limit (finalized_block=12345)
    BlockAboveHead:
      description: 'One of two codes for a `{number}` path parameter above
        `finalized_block` (see "Errors" above): `error.code = "not_indexed_yet"`
        when `{number}` is above `as_of_block` (not indexed at all yet --
        carries `indexed_through`, the highest indexed block), or `error.code =
        "finality_exceeded"` when it is at or below `as_of_block` (already
        indexed, just not yet reorg-safe).'
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorBody"
          examples:
            not_indexed_yet:
              value:
                error:
                  code: not_indexed_yet
                  message: block 999999999 has not been indexed yet (indexed through 12345)
                  indexed_through: 12345
            finality_exceeded:
              value:
                error:
                  code: finality_exceeded
                  message: block 12340 is above the finalized limit (finalized_block=12335)
  schemas:
    AddressInput:
      type: string
      description: 20-byte address. `0x`/`0X` prefix optional; either hex digit case
        is accepted.
      pattern: ^(0[xX])?[0-9a-fA-F]{40}$
      example: "0xAbCdEf0123456789aBcDeF0123456789aBCDEF01"
    HashInput:
      type: string
      description: 32-byte hash. `0x`/`0X` prefix optional; either hex digit case is
        accepted.
      pattern: ^(0[xX])?[0-9a-fA-F]{64}$
    Address:
      type: string
      description: 20-byte address, canonical form always `0x` + 40 lowercase hex digits.
      pattern: ^0x[0-9a-f]{40}$
    Hash32:
      type: string
      description: 32-byte hash/topic, canonical form always `0x` + 64 lowercase hex digits.
      pattern: ^0x[0-9a-f]{64}$
    HexBytes:
      type: string
      description: Raw bytes of any length, `0x` + an even number of lowercase hex
        digits (`"0x"` alone for zero bytes).
      pattern: ^0x([0-9a-f]{2})*$
    UInt256String:
      type: string
      description: Non-negative integer that may exceed 2^53, rendered as a plain
        decimal string — never a JSON number, never scientific or hex notation.
      pattern: ^[0-9]+$
      example: "9007199254740993"
    Int256String:
      type: string
      description: Signed integer that may exceed +-2^53, rendered as a plain decimal
        string, optionally sign-prefixed.
      pattern: ^-?[0-9]+$
    DecimalString:
      type: string
      description: Human-adjusted (decimals-scaled) fixed-point value rendered as a
        plain decimal string — never a JSON number.
      pattern: ^-?[0-9]+(\.[0-9]+)?$
    HexQuantity:
      type: string
      description: "`0x`-prefixed hexadecimal integer in standard Ethereum
        `callTracer` format; `value`/`gas`/`gasUsed` are `0x`-prefixed hex
        quantities."
      pattern: ^0x[0-9a-f]*$
    Timestamp:
      type: string
      format: date-time
      description: "`YYYY-MM-DDTHH:MM:SSZ`, UTC, second precision."
      example: 2026-09-26T05:41:07Z
    DateOnly:
      type: string
      format: date
      description: "`YYYY-MM-DD`, UTC calendar day."
      example: 2026-09-26
    ExtraJson:
      type: object
      description: Additional chain-specific fields as a JSON object; `{}` when there
        are none. Shape varies by chain.
      additionalProperties: true
    Chain:
      type: object
      description: "A chain this API serves: its identity and display name, what it
        serves (`features`), which blocks its data covers (`coverage`), how
        `finalized_block` is derived (`finality`) and its per-request caps
        (`limits`)."
      required:
        - chain
        - chain_slug
        - name
        - chain_id
        - chain_external_id
        - features
        - coverage
        - finality
        - limits
      properties:
        chain:
          type: string
          description: "Chain identifier to call with: the value of the `{chain}` path
            parameter. Always the exact lowercase form of `chain_slug`."
          example: robinhood_mainnet
        chain_slug:
          type: string
          description: Canonical uppercase chain slug; a stable key for joining with other
            systems. `chain` is always its lowercase form.
          example: ROBINHOOD_MAINNET
        name:
          type: string
          description: "Human-readable display name for UIs. Not an identifier: do not use
            it as a key or in URLs."
          example: Robinhood Chain
        chain_id:
          type: integer
          format: int64
          description: EIP-155 EVM chain ID.
          example: 4663
        chain_external_id:
          type: string
          description: CAIP-2 formatted external chain identifier (`eip155:{chain_id}`).
          example: eip155:4663
        features:
          type: array
          description: 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).
          items:
            type: string
            enum:
              - blocks
              - transactions
              - address_transactions
              - transfers
              - token_metadata
              - balances
              - holders
              - nfts
              - dex_swaps
              - dex_prices
              - stocks
              - traces
              - freshness
          example:
            - blocks
            - transactions
            - address_transactions
            - transfers
            - token_metadata
            - freshness
        coverage:
          $ref: "#/components/schemas/ChainCoverage"
        finality:
          $ref: "#/components/schemas/ChainFinality"
        limits:
          $ref: "#/components/schemas/ChainLimits"
    ChainCoverage:
      type: object
      description: Which blocks this chain's data covers.
      required:
        - history_mode
        - from_block
        - traces_from_block
      properties:
        history_mode:
          type: string
          enum:
            - full
            - window
          description: "`full`: every block from genesis. `window`: a rolling window of
            recent blocks (`retention_days`); `balances`, `holders` and `nfts`,
            which are only correct when built from genesis, are never served on
            such a chain."
        from_block:
          type:
            - integer
            - "null"
          format: int64
          description: "First block of the covered history: `0` on a `full` chain; on a
            `window` chain the coverage floor, which moves forward over time (by
            one retention partition, about 7 days of blocks, at a time; never
            backward). It is refreshed at most once a minute, and `GET /chains`
            and the endpoints use the same value. Block requests before it
            return `422 no_coverage`. `null` only on a `window` chain, only
            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` meanwhile. A `full` chain is never
            `null`. The property is always present. The example value is
            illustrative; on window chains the start moves forward roughly
            weekly — read `GET /chains` `coverage.from_block` at runtime."
          example: 26000000
        retention_days:
          type: integer
          description: "Length of the rolling window in days, a lower bound: the covered
            span is at least this and at most this + 8 days (38 days for 30).
            Present on `window` chains only."
          example: 30
        traces_from_block:
          type:
            - integer
            - "null"
          format: int64
          description: "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`."
          example: 72050949
    ChainFinality:
      type: object
      description: "How `meta.finalized_block` is derived on this chain: `as_of_block`
        minus a fixed block lag. A reorg-safety watermark, not consensus
        finality (see Finality in the API description)."
      required:
        - model
        - lag_blocks
      properties:
        model:
          type: string
          enum:
            - block_lag
        lag_blocks:
          type: integer
          format: int64
          description: The lag in blocks; blocks of different chains are not comparable.
          example: 64
    ChainLimits:
      type: object
      description: Per-request caps and the query concurrency this service enforces on
        this chain.
      required:
        - max_page_size
        - max_window_blocks
        - max_pools_for_token
        - max_batch_addresses
        - max_date_span_days
        - max_concurrent_queries
      properties:
        max_page_size:
          type: integer
          description: Largest `limit`; larger values are clamped to it.
          example: 500
        max_window_blocks:
          type: integer
          format: int64
          description: Widest `[from_block, to_block]` window of the windowed list
            endpoints (address transactions and transfers, DEX swaps by token).
          example: 100000
        max_pools_for_token:
          type: integer
          description: Most pools a `GET /{chain}/dex/swaps?token=` request may span.
          example: 200
        max_batch_addresses:
          type: integer
          description: Most addresses one `POST /{chain}/tokens:batch` request may ask for.
          example: 100
        max_date_span_days:
          type: integer
          description: Widest `from`..`to` date span of one `GET /{chain}/dex/prices`
            request, in days; a wider span is `409 span_exceeded`.
          example: 90
        max_concurrent_queries:
          type: integer
          minimum: 2
          description: 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.
          example: 2
    ChainsResponse:
      type: object
      required:
        - data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Chain"
    Meta:
      type: object
      description: Metadata present on every success response.
      required:
        - chain
        - chain_slug
        - chain_external_id
        - as_of_block
        - finalized_block
        - coverage
        - refreshed_at
      properties:
        chain:
          type: string
          description: Chain identifier; the value of the `{chain}` path parameter.
          example: robinhood_mainnet
        chain_slug:
          type: string
          description: Canonical uppercase chain slug; `chain` is always its lowercase form.
          example: ROBINHOOD_MAINNET
        chain_external_id:
          type: string
          description: CAIP-2 formatted external chain identifier (`eip155:{chain_id}`).
          example: eip155:4663
        as_of_block:
          type: integer
          format: int64
          description: The indexed head this response's finality watermark was computed
            from.
        finalized_block:
          type: integer
          format: int64
          description: Highest block height that block-scoped endpoints will serve; trails
            `as_of_block` by a fixed number of blocks set per chain. A
            reorg-safety watermark, not consensus finality; see Finality in the
            API description.
        coverage:
          type: string
          enum:
            - full
            - partial
          description: "`\"partial\"` appears only from `GET
            /{chain}/addresses/{address}/transactions` and `GET
            /{chain}/addresses/{address}/transfers`, when `clamp=true` narrowed
            the served window, and from those two, `GET
            /{chain}/tokens/{token}/transfers` and `GET /{chain}/dex/swaps` when
            the block window starts before the chain's first indexed block (see
            Coverage in the API description). Every other endpoint reports
            `\"full\"`."
        refreshed_at:
          $ref: "#/components/schemas/Timestamp"
          description: "When the data behind this response was last updated (UTC): the
            timestamp of `as_of_block` for block-based endpoints, the latest
            snapshot time for snapshot endpoints, and the last update time for
            token metadata and status."
    ErrorBody:
      type: object
      description: The only shape any non-2xx response ever takes. `code` and
        `message` are always present; `indexed_through` is present only on
        `error.code = "not_indexed_yet"` and absent (never `null`) otherwise. No
        other field is ever added.
      required:
        - error
      additionalProperties: false
      properties:
        error:
          type: object
          required:
            - code
            - message
          additionalProperties: false
          properties:
            code:
              type: string
              description: Stable machine-readable identifier; see each operation for the
                exact set of values it can return.
            message:
              type: string
              description: Free-form English text for logs/debugging. Do not pattern-match on
                it.
            indexed_through:
              type: integer
              format: int64
              description: Highest indexed block on this chain. Present only when `code =
                "not_indexed_yet"`.
            data:
              type: object
              description: Optional structured error details.
              additionalProperties: true
    Block:
      type: object
      required:
        - number
        - hash
        - parent_hash
        - timestamp
        - miner
        - gas_limit
        - gas_used
        - base_fee_per_gas
        - state_root
        - transactions_root
        - receipts_root
        - tx_count
        - size
        - l1_block_number
        - extra
      properties:
        number:
          type: integer
          format: int64
        hash:
          $ref: "#/components/schemas/Hash32"
        parent_hash:
          $ref: "#/components/schemas/Hash32"
        timestamp:
          $ref: "#/components/schemas/Timestamp"
        miner:
          $ref: "#/components/schemas/Address"
        gas_limit:
          type: integer
          format: int64
        gas_used:
          type: integer
          format: int64
        base_fee_per_gas:
          oneOf:
            - $ref: "#/components/schemas/UInt256String"
            - type: "null"
        state_root:
          $ref: "#/components/schemas/Hash32"
        transactions_root:
          $ref: "#/components/schemas/Hash32"
        receipts_root:
          $ref: "#/components/schemas/Hash32"
        tx_count:
          type: integer
        size:
          type: integer
        l1_block_number:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
          description: Present (non-null) only on L2 chains that record an L1 origin block.
        extra:
          $ref: "#/components/schemas/ExtraJson"
    BlockEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is never present (this endpoint has no pagination)."
      properties:
        data:
          $ref: "#/components/schemas/Block"
        meta:
          $ref: "#/components/schemas/Meta"
    Log:
      type: object
      required:
        - log_index
        - address
        - topics
        - data
        - extra
      properties:
        log_index:
          type: integer
        address:
          $ref: "#/components/schemas/Address"
        topics:
          type: array
          description: 0-4 entries; contiguous from `topic0` (an on-chain log's topics
            never have a gap).
          items:
            $ref: "#/components/schemas/Hash32"
          maxItems: 4
        data:
          $ref: "#/components/schemas/HexBytes"
        extra:
          $ref: "#/components/schemas/ExtraJson"
    Transaction:
      type: object
      required:
        - block_number
        - tx_index
        - hash
        - block_timestamp
        - type
        - from
        - to
        - value
        - nonce
        - gas
        - gas_price
        - max_fee_per_gas
        - max_priority_fee_per_gas
        - input
        - status
        - gas_used
        - cumulative_gas_used
        - effective_gas_price
        - contract_address
        - log_count
        - gas_used_for_l1
        - l1_block_number
        - extra
      properties:
        block_number:
          type: integer
          format: int64
        tx_index:
          type: integer
        hash:
          $ref: "#/components/schemas/Hash32"
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        type:
          type: integer
          minimum: 0
          maximum: 255
          description: EIP-2718 transaction type byte.
        from:
          $ref: "#/components/schemas/Address"
        to:
          oneOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
          description: "`null` for a contract-creation transaction."
        value:
          $ref: "#/components/schemas/UInt256String"
        nonce:
          type: integer
          format: int64
        gas:
          type: integer
          format: int64
        gas_price:
          oneOf:
            - $ref: "#/components/schemas/UInt256String"
            - type: "null"
        max_fee_per_gas:
          oneOf:
            - $ref: "#/components/schemas/UInt256String"
            - type: "null"
        max_priority_fee_per_gas:
          oneOf:
            - $ref: "#/components/schemas/UInt256String"
            - type: "null"
        input:
          $ref: "#/components/schemas/HexBytes"
        status:
          type: integer
          minimum: 0
          maximum: 255
          description: 1 = success, 0 = reverted (EIP-658 receipt status byte).
        gas_used:
          type: integer
          format: int64
        cumulative_gas_used:
          type: integer
          format: int64
        effective_gas_price:
          oneOf:
            - $ref: "#/components/schemas/UInt256String"
            - type: "null"
        contract_address:
          oneOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
          description: Set only for a contract-creation transaction.
        log_count:
          type: integer
        gas_used_for_l1:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
          description: L2-specific; `null` on chains with no L1 data-fee accounting.
        l1_block_number:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
        extra:
          $ref: "#/components/schemas/ExtraJson"
    TransactionWithLogs:
      allOf:
        - $ref: "#/components/schemas/Transaction"
        - type: object
          properties:
            logs:
              type: array
              description: Present only when the request had `?include_logs=true`.
              items:
                $ref: "#/components/schemas/Log"
    TransactionListEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is present only when there is another page."
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Transaction"
        next_cursor:
          type: string
          description: Opaque pagination token from the previous response's `next_cursor`;
            pass it back unchanged.
        meta:
          $ref: "#/components/schemas/Meta"
    TransactionPointEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is never present (this endpoint has no pagination)."
      properties:
        data:
          $ref: "#/components/schemas/TransactionWithLogs"
        meta:
          $ref: "#/components/schemas/Meta"
    Erc20Transfer:
      type: object
      required:
        - token
        - standard
        - from
        - to
        - amount
        - block_number
        - block_timestamp
        - tx_hash
        - tx_index
        - log_index
      properties:
        token:
          $ref: "#/components/schemas/Address"
        standard:
          type: string
          const: erc20
        from:
          $ref: "#/components/schemas/Address"
        to:
          $ref: "#/components/schemas/Address"
        amount:
          $ref: "#/components/schemas/UInt256String"
        block_number:
          type: integer
          format: int64
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
        tx_index:
          type: integer
        log_index:
          type: integer
    Erc721Transfer:
      type: object
      required:
        - token
        - standard
        - from
        - to
        - token_id
        - block_number
        - block_timestamp
        - tx_hash
        - tx_index
        - log_index
      properties:
        token:
          $ref: "#/components/schemas/Address"
        standard:
          type: string
          const: erc721
        from:
          $ref: "#/components/schemas/Address"
        to:
          $ref: "#/components/schemas/Address"
        token_id:
          $ref: "#/components/schemas/UInt256String"
        block_number:
          type: integer
          format: int64
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
        tx_index:
          type: integer
        log_index:
          type: integer
    Erc1155Transfer:
      type: object
      required:
        - token
        - standard
        - operator
        - from
        - to
        - token_id
        - value
        - block_number
        - block_timestamp
        - tx_hash
        - tx_index
        - log_index
        - batch_index
      properties:
        token:
          $ref: "#/components/schemas/Address"
        standard:
          type: string
          const: erc1155
        operator:
          $ref: "#/components/schemas/Address"
        from:
          $ref: "#/components/schemas/Address"
        to:
          $ref: "#/components/schemas/Address"
        token_id:
          $ref: "#/components/schemas/UInt256String"
        value:
          $ref: "#/components/schemas/UInt256String"
        block_number:
          type: integer
          format: int64
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
        tx_index:
          type: integer
        log_index:
          type: integer
        batch_index:
          type: integer
    TokenTransferListEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is present only when the page returned exactly
        `limit` rows (optimistic pagination: it may turn out to be the last page
        anyway)."
      properties:
        data:
          type: array
          items:
            oneOf:
              - $ref: "#/components/schemas/Erc20Transfer"
              - $ref: "#/components/schemas/Erc721Transfer"
              - $ref: "#/components/schemas/Erc1155Transfer"
        next_cursor:
          type: string
          description: Opaque pagination token from the previous response's `next_cursor`;
            pass it back unchanged.
        meta:
          $ref: "#/components/schemas/Meta"
    AddressTransferListEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is present only when the page returned exactly
        `limit` rows (optimistic pagination: it may turn out to be the last page
        anyway)."
      properties:
        data:
          type: array
          items:
            oneOf:
              - $ref: "#/components/schemas/Erc20Transfer"
              - $ref: "#/components/schemas/Erc721Transfer"
        next_cursor:
          type: string
          description: Opaque pagination token from the previous response's `next_cursor`;
            pass it back unchanged.
        meta:
          $ref: "#/components/schemas/Meta"
    AddressBalance:
      type: object
      required:
        - token
        - balance
        - symbol
        - decimals
      properties:
        token:
          $ref: "#/components/schemas/Address"
        balance:
          $ref: "#/components/schemas/UInt256String"
        symbol:
          oneOf:
            - type: string
            - type: "null"
        decimals:
          oneOf:
            - type: integer
              minimum: 0
              maximum: 255
            - type: "null"
    AddressBalanceListEnvelope:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AddressBalance"
        next_cursor:
          type: string
          description: Opaque pagination token from the previous response's `next_cursor`;
            pass it back unchanged.
        meta:
          $ref: "#/components/schemas/Meta"
    TokenHolder:
      type: object
      required:
        - token
        - holder
        - balance
      properties:
        token:
          $ref: "#/components/schemas/Address"
        holder:
          $ref: "#/components/schemas/Address"
        balance:
          $ref: "#/components/schemas/UInt256String"
    TokenHolderListEnvelope:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TokenHolder"
        next_cursor:
          type: string
          description: Opaque pagination token from the previous response's `next_cursor`;
            pass it back unchanged.
        meta:
          $ref: "#/components/schemas/Meta"
    Token:
      type: object
      required:
        - address
        - standard
        - name
        - symbol
        - decimals
        - total_supply
        - first_seen_block
        - metadata_updated_at
        - metadata_block
        - metadata_status
        - metadata_issues
      properties:
        address:
          $ref: "#/components/schemas/Address"
        standard:
          type: string
          enum:
            - erc20
            - erc721
            - unknown
        name:
          oneOf:
            - type: string
            - type: "null"
        symbol:
          oneOf:
            - type: string
            - type: "null"
        decimals:
          oneOf:
            - type: integer
              minimum: 0
              maximum: 255
            - type: "null"
        total_supply:
          oneOf:
            - $ref: "#/components/schemas/UInt256String"
            - type: "null"
          description: Raw on-chain integer, no `decimals` scaling applied server-side.
        first_seen_block:
          type: integer
          format: int64
        metadata_updated_at:
          $ref: "#/components/schemas/Timestamp"
          description: When this token's metadata was last updated (UTC).
        metadata_block:
          type: integer
          format: int64
          description: Block height at which this token's metadata was read.
        metadata_status:
          type: string
          enum:
            - ok
            - partial
            - unavailable
          description: Overall status of the token metadata.
        metadata_issues:
          type: object
          description: Issues encountered while fetching individual metadata fields. Key
            is the field name; value is the issue category.
          properties:
            name:
              type: string
              enum:
                - reverted
                - no_data
                - invalid_encoding
                - temporarily_unavailable
            symbol:
              type: string
              enum:
                - reverted
                - no_data
                - invalid_encoding
                - temporarily_unavailable
            decimals:
              type: string
              enum:
                - reverted
                - no_data
                - invalid_encoding
                - temporarily_unavailable
            total_supply:
              type: string
              enum:
                - reverted
                - no_data
                - invalid_encoding
                - temporarily_unavailable
          additionalProperties: false
    TokenEnvelope:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          $ref: "#/components/schemas/Token"
        meta:
          $ref: "#/components/schemas/Meta"
    TokensBatchRequest:
      type: object
      required:
        - addresses
      properties:
        addresses:
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/AddressInput"
    TokensBatchEnvelope:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          type: object
          required:
            - tokens
            - missing
          properties:
            tokens:
              type: array
              items:
                $ref: "#/components/schemas/Token"
            missing:
              type: array
              description: Canonical (`0x`-lowercase) addresses from the request with no
                matching metadata, first-occurrence request order, deduplicated.
              items:
                $ref: "#/components/schemas/Address"
        meta:
          $ref: "#/components/schemas/Meta"
    Erc721Nft:
      type: object
      required:
        - standard
        - contract
        - token
        - token_id
        - owner
        - block_number
        - log_index
        - block_timestamp
        - tx_hash
      properties:
        standard:
          type: string
          const: erc721
        contract:
          $ref: "#/components/schemas/Address"
        token:
          $ref: "#/components/schemas/Address"
          description: Always equal to `contract`.
        token_id:
          $ref: "#/components/schemas/UInt256String"
        owner:
          $ref: "#/components/schemas/Address"
        block_number:
          type: integer
          format: int64
          description: The block the current owner's transfer was logged in.
        log_index:
          type: integer
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
    Erc1155NftHolders:
      type: object
      required:
        - standard
        - contract
        - token
        - token_id
        - holders
      properties:
        standard:
          type: string
          const: erc1155
        contract:
          $ref: "#/components/schemas/Address"
        token:
          $ref: "#/components/schemas/Address"
          description: Always equal to `contract`.
        token_id:
          $ref: "#/components/schemas/UInt256String"
        holders:
          type: array
          items:
            type: object
            required:
              - holder
              - balance
            properties:
              holder:
                $ref: "#/components/schemas/Address"
              balance:
                $ref: "#/components/schemas/Int256String"
    NftPointEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is never present (no pagination for a single
        `(contract, token_id)`)."
      properties:
        data:
          oneOf:
            - $ref: "#/components/schemas/Erc721Nft"
            - $ref: "#/components/schemas/Erc1155NftHolders"
        meta:
          $ref: "#/components/schemas/Meta"
    Erc721NftListItem:
      allOf:
        - $ref: "#/components/schemas/Erc721Nft"
      description: Same shape as the single ERC-721 object; `owner` always equals the
        request's `?owner=`.
    Erc1155NftListItem:
      type: object
      required:
        - standard
        - contract
        - token
        - token_id
        - owner
        - balance
      description: Flattened one row per `(token, id, holder)` — note this differs
        from the single ERC-1155 shape (`Erc1155NftHolders`), which nests a
        `holders` array instead of repeating `owner`/`balance` per row.
      properties:
        standard:
          type: string
          const: erc1155
        contract:
          $ref: "#/components/schemas/Address"
        token:
          $ref: "#/components/schemas/Address"
        token_id:
          $ref: "#/components/schemas/UInt256String"
        owner:
          $ref: "#/components/schemas/Address"
          description: Always equal to the request's `?owner=`.
        balance:
          $ref: "#/components/schemas/Int256String"
    NftListEnvelope:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          type: array
          items:
            oneOf:
              - $ref: "#/components/schemas/Erc721NftListItem"
              - $ref: "#/components/schemas/Erc1155NftListItem"
        next_cursor:
          type: string
          description: Opaque pagination token from the previous response's `next_cursor`;
            pass it back unchanged.
        meta:
          $ref: "#/components/schemas/Meta"
    DexSwap:
      type: object
      required:
        - protocol
        - pool_key
        - amount0
        - amount1
        - sqrt_price_x96
        - liquidity
        - tick
        - lp_fee
        - sender
        - recipient
        - block_number
        - block_timestamp
        - tx_hash
        - tx_index
        - log_index
      properties:
        protocol:
          type: string
          description: e.g. "uniswap_v3".
        pool_key:
          $ref: "#/components/schemas/Hash32"
          description: 32-byte key; a V2/V3 pool address is left-zero-padded into this
            shape.
        amount0:
          $ref: "#/components/schemas/Int256String"
        amount1:
          $ref: "#/components/schemas/Int256String"
        sqrt_price_x96:
          $ref: "#/components/schemas/UInt256String"
        liquidity:
          $ref: "#/components/schemas/UInt256String"
        tick:
          type: integer
          format: int32
        lp_fee:
          oneOf:
            - type: integer
            - type: "null"
        sender:
          $ref: "#/components/schemas/Address"
        recipient:
          oneOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
        block_number:
          type: integer
          format: int64
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
        tx_index:
          type: integer
        log_index:
          type: integer
    DexSwapListEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is present only when the page returned exactly
        `limit` rows."
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DexSwap"
        next_cursor:
          type: string
          description: Opaque pagination token from the previous response's `next_cursor`;
            pass it back unchanged.
        meta:
          $ref: "#/components/schemas/Meta"
    DexDailyPrice:
      type: object
      required:
        - day
        - token
        - token_symbol
        - token_name
        - quote_token
        - quote_symbol
        - quote_name
        - base_decimals
        - quote_decimals
        - swap_count
        - base_volume_raw
        - quote_volume_raw
        - base_volume
        - quote_volume
        - vwap
        - first_price
        - last_price
        - min_price
        - max_price
        - first_price_numerator
        - first_price_denominator
        - last_price_numerator
        - last_price_denominator
        - min_price_numerator
        - min_price_denominator
        - max_price_numerator
        - max_price_denominator
        - refreshed_at
      properties:
        day:
          $ref: "#/components/schemas/DateOnly"
        token:
          $ref: "#/components/schemas/Address"
        token_symbol:
          oneOf:
            - type: string
            - type: "null"
        token_name:
          oneOf:
            - type: string
            - type: "null"
        quote_token:
          $ref: "#/components/schemas/Address"
          description: The all-zero address represents native ETH as the quote asset.
        quote_symbol:
          oneOf:
            - type: string
            - type: "null"
          description: '`"ETH"` when `quote_token` is the zero address.'
        quote_name:
          oneOf:
            - type: string
            - type: "null"
          description: '`"Ether"` when `quote_token` is the zero address.'
        base_decimals:
          oneOf:
            - type: integer
              minimum: 0
              maximum: 255
            - type: "null"
        quote_decimals:
          oneOf:
            - type: integer
              minimum: 0
              maximum: 255
            - type: "null"
          description: "`18` when `quote_token` is the zero address."
        swap_count:
          type: integer
          format: int64
        base_volume_raw:
          $ref: "#/components/schemas/UInt256String"
        quote_volume_raw:
          $ref: "#/components/schemas/UInt256String"
        base_volume:
          oneOf:
            - $ref: "#/components/schemas/DecimalString"
            - type: "null"
          description: "`base_volume_raw` scaled by `base_decimals`; `null` when
            `base_decimals` is unknown."
        quote_volume:
          oneOf:
            - $ref: "#/components/schemas/DecimalString"
            - type: "null"
        vwap:
          oneOf:
            - $ref: "#/components/schemas/DecimalString"
            - type: "null"
        first_price:
          oneOf:
            - $ref: "#/components/schemas/DecimalString"
            - type: "null"
        last_price:
          oneOf:
            - $ref: "#/components/schemas/DecimalString"
            - type: "null"
        min_price:
          oneOf:
            - $ref: "#/components/schemas/DecimalString"
            - type: "null"
        max_price:
          oneOf:
            - $ref: "#/components/schemas/DecimalString"
            - type: "null"
        first_price_numerator:
          $ref: "#/components/schemas/UInt256String"
        first_price_denominator:
          $ref: "#/components/schemas/UInt256String"
        last_price_numerator:
          $ref: "#/components/schemas/UInt256String"
        last_price_denominator:
          $ref: "#/components/schemas/UInt256String"
        min_price_numerator:
          $ref: "#/components/schemas/UInt256String"
        min_price_denominator:
          $ref: "#/components/schemas/UInt256String"
        max_price_numerator:
          $ref: "#/components/schemas/UInt256String"
        max_price_denominator:
          $ref: "#/components/schemas/UInt256String"
        refreshed_at:
          $ref: "#/components/schemas/Timestamp"
    DexPriceListEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is never present (this endpoint has no pagination)."
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DexDailyPrice"
        meta:
          $ref: "#/components/schemas/Meta"
    StockDaily:
      type: object
      required:
        - day
        - token
        - symbol
        - name
        - transfers
        - unique_senders
        - unique_receivers
        - mint_raw_amount
        - burn_raw_amount
        - net_supply_change
        - holder_count
        - top10_holder_share_bps
        - dex_swap_count
        - dex_raw_volume
        - refreshed_at
      properties:
        day:
          $ref: "#/components/schemas/DateOnly"
        token:
          $ref: "#/components/schemas/Address"
        symbol:
          type: string
        name:
          type: string
          description: Empty string when no matching name metadata is available.
        transfers:
          type: integer
          format: int64
        unique_senders:
          type: integer
          format: int64
        unique_receivers:
          type: integer
          format: int64
        mint_raw_amount:
          $ref: "#/components/schemas/UInt256String"
        burn_raw_amount:
          $ref: "#/components/schemas/UInt256String"
        net_supply_change:
          $ref: "#/components/schemas/Int256String"
        holder_count:
          type: integer
          format: int64
        top10_holder_share_bps:
          type: integer
          description: Basis points (0-10000).
        dex_swap_count:
          type: integer
          format: int64
        dex_raw_volume:
          $ref: "#/components/schemas/UInt256String"
        refreshed_at:
          $ref: "#/components/schemas/Timestamp"
    StockDailyListEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is never present (this endpoint has no pagination)."
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/StockDaily"
        meta:
          $ref: "#/components/schemas/Meta"
    StockDailyMetric:
      type: object
      required:
        - day
        - transfers
        - unique_senders
        - unique_receivers
        - mint_raw_amount
        - burn_raw_amount
        - net_supply_change
        - holder_count
        - top10_holder_share_bps
        - dex_swap_count
        - dex_raw_volume
        - refreshed_at
      properties:
        day:
          $ref: "#/components/schemas/DateOnly"
        transfers:
          type: integer
          format: int64
        unique_senders:
          type: integer
          format: int64
        unique_receivers:
          type: integer
          format: int64
        mint_raw_amount:
          $ref: "#/components/schemas/UInt256String"
        burn_raw_amount:
          $ref: "#/components/schemas/UInt256String"
        net_supply_change:
          $ref: "#/components/schemas/Int256String"
        holder_count:
          type: integer
          format: int64
        top10_holder_share_bps:
          type: integer
        dex_swap_count:
          type: integer
          format: int64
        dex_raw_volume:
          $ref: "#/components/schemas/UInt256String"
        refreshed_at:
          $ref: "#/components/schemas/Timestamp"
    StockToken:
      type: object
      required:
        - address
        - symbol
        - name
        - decimals
        - created_block
        - created_tx_hash
        - factory
        - creator
        - mint_address
        - burn_address
        - refreshed_at
        - daily
      properties:
        address:
          $ref: "#/components/schemas/Address"
        symbol:
          type: string
        name:
          type: string
        decimals:
          oneOf:
            - type: integer
              minimum: 0
              maximum: 255
            - type: "null"
        created_block:
          type: integer
          format: int64
        created_tx_hash:
          $ref: "#/components/schemas/Hash32"
        factory:
          $ref: "#/components/schemas/Address"
        creator:
          oneOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
        mint_address:
          oneOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
        burn_address:
          oneOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
        refreshed_at:
          $ref: "#/components/schemas/Timestamp"
        daily:
          type: array
          description: Most recent 30 days of daily metrics, newest first.
          items:
            $ref: "#/components/schemas/StockDailyMetric"
          maxItems: 30
    StockTokenEnvelope:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          $ref: "#/components/schemas/StockToken"
        meta:
          $ref: "#/components/schemas/Meta"
    CallFrame:
      type: object
      description: "A single `callTracer` call frame in standard Ethereum `callTracer`
        format; `value`/`gas`/`gasUsed` are `0x`-prefixed hex quantities. Any
        additional fields in the call frame are preserved
        (`additionalProperties: true`)."
      required:
        - type
        - from
        - gas
        - gasUsed
        - input
      properties:
        type:
          type: string
          description: e.g. `CALL`, `DELEGATECALL`, `STATICCALL`, `CREATE`, `CREATE2`,
            `SELFDESTRUCT`.
        from:
          $ref: "#/components/schemas/Address"
        to:
          $ref: "#/components/schemas/Address"
          description: Absent for a `CREATE`/`CREATE2` frame's target (the address does
            not exist yet at call time in the node's own output).
        value:
          $ref: "#/components/schemas/HexQuantity"
          description: Absent for a `STATICCALL` frame (no value can move).
        gas:
          $ref: "#/components/schemas/HexQuantity"
        gasUsed:
          $ref: "#/components/schemas/HexQuantity"
        input:
          $ref: "#/components/schemas/HexBytes"
        output:
          $ref: "#/components/schemas/HexBytes"
          description: Absent when the call returned no data.
        error:
          type: string
          description: Absent on a successful call.
        revertReason:
          type: string
          description: Absent unless the call reverted with `Error(string)` data.
        calls:
          type: array
          description: Nested sub-calls, in call order. Absent for a leaf frame.
          items:
            $ref: "#/components/schemas/CallFrame"
      additionalProperties: true
    BlockTraceItem:
      type: object
      required:
        - txHash
        - result
      properties:
        txHash:
          $ref: "#/components/schemas/Hash32"
        result:
          $ref: "#/components/schemas/CallFrame"
    BlockTracesEnvelope:
      type: object
      required:
        - data
        - meta
      description: Unpaginated; `next_cursor` is never present.
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BlockTraceItem"
        meta:
          $ref: "#/components/schemas/Meta"
    TxTraceEnvelope:
      type: object
      required:
        - data
        - meta
      description: Unpaginated; `next_cursor` is never present.
      properties:
        data:
          $ref: "#/components/schemas/CallFrame"
        meta:
          $ref: "#/components/schemas/Meta"
    FreshnessRow:
      type: object
      required:
        - dataset
        - category
        - max_block_number
        - max_day
        - max_time
        - seconds_behind
        - blocks_behind
        - days_behind
        - checked_at
      properties:
        dataset:
          type: string
          description: Public dataset identifier.
          enum:
            - blocks
            - transactions
            - logs
            - traces
            - erc20_transfers
            - erc721_transfers
            - erc1155_transfers
            - token_balances
            - erc1155_balances
            - tokens
            - nft_owners
            - dex_swaps
            - dex_prices
            - stocks
            - stock_daily
          example: blocks
        category:
          type: string
          enum:
            - raw
            - derived
          description: Dataset category classification (`raw` for core chain data,
            `derived` for computed datasets).
          example: raw
        max_block_number:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
        max_day:
          oneOf:
            - $ref: "#/components/schemas/DateOnly"
            - type: "null"
        max_time:
          oneOf:
            - $ref: "#/components/schemas/Timestamp"
            - type: "null"
        seconds_behind:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
        blocks_behind:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
        days_behind:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
        coverage_from_block:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
          description: Lowest block number indexed with traces. Present only when `dataset
            = "traces"`.
        coverage_to_block:
          oneOf:
            - type: integer
              format: int64
            - type: "null"
          description: Highest block number indexed with traces. Present only when
            `dataset = "traces"`.
        coverage_complete:
          type: boolean
          description: Whether trace coverage between `coverage_from_block` and
            `coverage_to_block` is complete. Present only when `dataset =
            "traces"`.
        checked_at:
          $ref: "#/components/schemas/Timestamp"
      example:
        dataset: blocks
        category: raw
        max_block_number: 72313256
        max_day: null
        max_time: 2026-09-28T03:41:07Z
        seconds_behind: 0
        blocks_behind: 0
        days_behind: null
        checked_at: 2026-09-28T03:41:10Z
    FreshnessEnvelope:
      type: object
      required:
        - data
        - meta
      description: "`next_cursor` is never present (this endpoint has no pagination)."
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/FreshnessRow"
        meta:
          $ref: "#/components/schemas/Meta"
  securitySchemes:
    ApiKeyHeader:
      type: apiKey
      in: header
      name: x-api-key
      description: Your BlockVectra API key.
