> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.umbraprivacy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tree Notes

> Returns a paginated list of Stealth Pool Note records for a specific Merkle tree, ordered by insertion index ascending.

Use this endpoint when you know which tree you want to scan. For global scans across all trees, use [Global Notes](/indexer/api-reference/utxos).

<Note>
  The path retains the legacy `/v1/trees/{tree_index}/utxos` segment. The records are V18 Stealth Pool Notes.
</Note>

## Response Layouts

The `X-Response-Layout` header controls how records are packed in the protobuf response:

* **Row-oriented** (default, omit header): each note is a self-contained `UtxoDataItem`. Easy to iterate record by record.
* **Columnar** (set header to `"columnar"`): all fields across notes are packed into parallel arrays. Significantly smaller on the wire — preferred for data pipelines and bulk processing.

<Note>
  The Umbra SDK uses row-oriented layout internally. Use columnar layout only if you are building a custom bulk processing pipeline.
</Note>

## Pagination

Initialise with `cursor = tree_index × 1,048,576`. Each response includes a `next_cursor` field. Repeat requests using `cursor = next_cursor` until the response contains fewer records than `limit`.

```bash theme={null}
# First page of tree 0.
curl "https://utxo-indexer.api.umbraprivacy.com/v1/trees/0/utxos?cursor=0&limit=1000"

# Next page (using next_cursor from previous response).
curl "https://utxo-indexer.api.umbraprivacy.com/v1/trees/0/utxos?cursor=1000&limit=1000"
```


## OpenAPI

````yaml GET /v1/trees/{tree_index}/utxos
openapi: 3.0.3
info:
  title: Umbra Indexer Read Service
  description: >
    Read-only REST API for querying Umbra mixer tree state, UTXO records,

    and Merkle inclusion proofs.


    ## Response Encoding


    **All endpoints** support `application/x-protobuf` encoding. The encoding

    strategy differs by endpoint category:


    - **Always Protobuf** (no content negotiation): stats, tree metadata, Merkle
    proofs,
      and all UTXO data endpoints. These endpoints always respond with
      `Content-Type: application/x-protobuf` regardless of the `Accept` header.
    - **Content negotiation** (health endpoints only): respond with JSON by
    default,
      or Protobuf when `Accept: application/x-protobuf` is set. Send
      `Accept: application/x-protobuf` for consistent protobuf-only clients.

    ## UTXO Response Layouts


    The three UTXO data endpoints (`GET /v1/utxos`, `GET
    /v1/utxos/{absolute_index}`,

    `GET /v1/trees/{tree_index}/utxos`) support two Protobuf response layouts

    controlled by the `X-Response-Layout` request header:


    - **Row-oriented** (default) -- `UtxoResponse` message: each UTXO is a
      self-contained `UtxoDataItem` sub-message. Easier to iterate record-by-record.
    - **Columnar** (`X-Response-Layout: columnar`) -- `UtxoColumnarResponse`
    message:
      each field across all UTXOs is packed into a parallel array inside a single
      `UtxoColumns` sub-message. Compresses significantly better over the wire and is
      preferred by vectorized consumers (e.g. data pipelines, analytics).

    ## Rate Limiting


    All endpoints are subject to rate limiting. Exceeded limits return `429 Too
    Many Requests`.


    ## Compression


    All responses are compressed. Send `Accept-Encoding: gzip, br`.


    ## Absolute Index


    The **absolute index** is a globally monotonic cursor across all Merkle
    trees:

    ```

    absolute_index = tree_index * MAX_LEAVES_PER_TREE + insertion_index

    ```

    where `MAX_LEAVES_PER_TREE = 1,048,576` (2^20).
  version: 0.1.0
  contact:
    name: Umbra Protocol
servers:
  - url: https://utxo-indexer.api.umbraprivacy.com
    description: Mainnet
  - url: https://utxo-indexer.api-devnet.umbraprivacy.com
    description: Devnet
security: []
tags:
  - name: health
    description: |
      Health and readiness probes for Kubernetes or load-balancer checks.
      Support both JSON and Protobuf via `Accept` header negotiation.
  - name: stats
    description: Aggregate statistics for the UTXO index. Always Protobuf.
  - name: trees
    description: Per-tree Merkle metadata and Merkle inclusion proofs. Always Protobuf.
  - name: utxos
    description: >
      UTXO data queries with absolute-index-based pagination. Always Protobuf.

      Supports row-oriented and columnar response layouts via
      `X-Response-Layout`.
paths:
  /v1/trees/{tree_index}/utxos:
    get:
      tags:
        - trees
        - utxos
      summary: Paginated UTXO records for a specific tree
      description: >
        Returns a paginated page of UTXO records belonging to the specified
        Merkle

        tree, ordered by `absolute_index` ascending (= insertion order).


        **Always Protobuf** -- responds with `application/x-protobuf` regardless

        of the `Accept` header.


        ## Response layout


        Set the `X-Response-Layout` header to switch between encoding
        strategies:

        - **Row-oriented** (default, `X-Response-Layout` absent or any other
        value):
          `UtxoResponse` -- each UTXO is a self-contained `UtxoDataItem` message.
        - **Columnar** (`X-Response-Layout: columnar`): `UtxoColumnarResponse`
        --
          fields are transposed into parallel arrays. Smaller wire size and preferred
          by data-pipeline consumers.

        ## Pagination


        The `cursor` parameter is an **absolute index** (not a tree-local
        insertion

        index). Initialize it to `tree_index * MAX_LEAVES_PER_TREE` for the
        first

        page, then use `next_cursor` from each response for subsequent pages.
      operationId: getUtxosByTree
      parameters:
        - name: tree_index
          in: path
          required: true
          description: Zero-based index of the Merkle tree whose UTXOs to fetch.
          schema:
            type: integer
            format: int64
            minimum: 0
          example: 0
        - name: cursor
          in: query
          required: false
          description: >
            Absolute index at which to start the current page (inclusive).

            Defaults to `tree_index * MAX_LEAVES_PER_TREE` (first slot of the
            tree).

            Values below the tree's start boundary are clamped up.
          schema:
            type: integer
            format: int64
            minimum: 0
          example: 1048576
        - name: limit
          in: query
          required: false
          description: |
            Maximum records per page. Default: `1000`. Maximum: `5000`.
            Passing `0` uses the default.
          schema:
            type: integer
            format: int64
            minimum: 0
            maximum: 5000
            default: 1000
          example: 1000
        - name: X-Response-Layout
          in: header
          required: false
          description: >
            Set to `"columnar"` to receive a `UtxoColumnarResponse`
            (struct-of-arrays).

            Omit or use any other value for the default row-oriented
            `UtxoResponse`.
          schema:
            type: string
            enum:
              - columnar
      responses:
        '200':
          description: UTXO records for the specified tree.
          content:
            application/x-protobuf:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/UtxoResponse'
                  - $ref: '#/components/schemas/UtxoColumnarResponse'
                discriminator:
                  propertyName: X-Response-Layout
        '400':
          description: Invalid `tree_index` or pagination parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Storage backend error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    UtxoResponse:
      type: object
      description: >
        Protobuf `UtxoResponse` message -- row-oriented paginated UTXO response.


        Returned by `GET /v1/utxos` and `GET /v1/trees/{tree_index}/utxos` when

        `X-Response-Layout` is absent or set to any value other than
        `"columnar"`.


        Each UTXO is encoded as a self-contained `UtxoDataItem` sub-message.

        Use `next_cursor` as the `start` (or `cursor`) parameter of the next

        request to retrieve the following page.
      required:
        - items
        - has_more
        - total_count
        - start_index
      properties:
        items:
          type: array
          description: Up to `limit` UTXO records in ascending `absolute_index` order.
          items:
            $ref: '#/components/schemas/UtxoDataItem'
        has_more:
          type: boolean
          description: '`true` if additional records exist beyond this page.'
          example: true
        next_cursor:
          type: integer
          format: int64
          nullable: true
          description: |
            Absolute index to pass as `start` (or `cursor`) for the next page.
            Absent when `has_more` is `false`.
          example: 1001
        total_count:
          type: integer
          format: int64
          description: >-
            Total number of matching records in the requested range across all
            pages.
          example: 5000
        start_index:
          type: integer
          format: int64
          description: Inclusive lower bound of the absolute index range that was queried.
          example: 0
        end_index:
          type: integer
          format: int64
          nullable: true
          description: |
            Inclusive upper bound of the absolute index range that was queried.
            Absent when no explicit `end` (or tree boundary) was provided.
          example: 4999
    UtxoColumnarResponse:
      type: object
      description: >
        Protobuf `UtxoColumnarResponse` message -- columnar paginated UTXO
        response.


        Returned by `GET /v1/utxos` and `GET /v1/trees/{tree_index}/utxos` when

        `X-Response-Layout: columnar` is set.


        All UTXO fields are transposed into parallel arrays inside `columns`.

        This layout eliminates per-field Protobuf metadata overhead on repeated

        records and compresses significantly better than row-oriented encoding
        --

        prefer this layout for bulk data transfers and data pipeline consumers.
      required:
        - count
        - has_more
        - total_count
        - start_index
        - columns
      properties:
        count:
          type: integer
          description: >-
            Number of rows (UTXOs) in this page. Length of every array in
            `columns`.
          example: 1000
        has_more:
          type: boolean
          description: '`true` if additional records exist beyond this page.'
          example: true
        next_cursor:
          type: integer
          format: int64
          nullable: true
          description: Absolute index to use as `start` (or `cursor`) for the next page.
          example: 1001
        total_count:
          type: integer
          format: int64
          description: Total matching records across all pages.
          example: 5000
        start_index:
          type: integer
          format: int64
          description: Inclusive lower bound of the absolute index range queried.
          example: 0
        end_index:
          type: integer
          format: int64
          nullable: true
          description: Inclusive upper bound queried (absent when unbounded).
          example: 4999
        columns:
          $ref: '#/components/schemas/UtxoColumns'
    ErrorResponse:
      type: object
      description: Standard JSON error body returned on 4xx and 5xx responses.
      required:
        - error
        - message
      properties:
        error:
          type: string
          description: |
            Short error category, e.g. `"Bad Request"`, `"Not Found"`,
            `"Too Many Requests"`, `"Internal Server Error"`.
          example: Not Found
        message:
          type: string
          description: Human-readable explanation of what went wrong.
          example: Tree 99 not found
    UtxoDataItem:
      type: object
      description: >
        Protobuf `UtxoDataItem` message -- a single UTXO record as it appears in

        `UtxoResponse.items` and `SingleUtxoResponse.utxo`.


        All binary fields (`final_commitment`, `h1_sender_address`,
        `h1_mint_address`,

        `h1_circuit_provable_hash`, `h1_smart_program_provable_hash`, `h1_hash`,

        `h2_hash`, `aes_encrypted_data`, `depositor_x25519_public_key`) are
        Protobuf

        `bytes` fields carrying the raw little-endian bytes (no base64 or hex
        encoding

        at the wire level).


        The 128-bit integer fields `h1_version` and `h1_commitment_index` are
        encoded

        as Protobuf `bytes` fields containing their **16-byte little-endian**
        binary

        representation.
      required:
        - absolute_index
        - tree_index
        - insertion_index
        - final_commitment
        - h1_version
        - h1_commitment_index
        - h1_sender_address
        - h1_mint_address
        - h1_relayer_fixed_sol_fees
        - h1_year
        - h1_month
        - h1_day
        - h1_hour
        - h1_minute
        - h1_second
        - h1_purpose
        - h1_circuit_provable_hash
        - h1_smart_program_provable_hash
        - h1_hash
        - h2_hash
        - aes_encrypted_data
        - depositor_x25519_public_key
        - timestamp
        - slot
        - event_type
      properties:
        absolute_index:
          type: integer
          format: int64
          description: |
            `tree_index * MAX_LEAVES_PER_TREE + insertion_index`. Monotonically
            increasing pagination cursor. `MAX_LEAVES_PER_TREE = 1,048,576`.
          example: 1048620
        tree_index:
          type: integer
          format: int64
          description: Zero-based Merkle tree index this UTXO belongs to.
          example: 1
        insertion_index:
          type: integer
          format: int64
          description: Zero-based leaf position within `tree_index` (0 to 1,048,575).
          example: 44
        final_commitment:
          type: string
          format: byte
          description: >
            Raw 32-byte `Poseidon(h1_hash, h2_hash)` -- the leaf value inserted
            into

            the Merkle tree (little-endian byte order, Protobuf `bytes`).
        h1_version:
          type: string
          format: byte
          description: >
            16-byte little-endian encoding of the `u128` protocol version used
            as a

            domain separator in the H1 hash circuit (Protobuf `bytes`).
        h1_commitment_index:
          type: string
          format: byte
          description: >
            16-byte little-endian encoding of the `u128` on-chain commitment
            counter

            fed into the H1 circuit (Protobuf `bytes`).
        h1_sender_address:
          type: string
          format: byte
          description: Raw 32-byte sender public key, little-endian (Protobuf `bytes`).
        h1_mint_address:
          type: string
          format: byte
          description: >-
            Raw 32-byte SPL token mint public key, little-endian (Protobuf
            `bytes`).
        h1_relayer_fixed_sol_fees:
          type: integer
          format: int64
          description: Relayer fixed fee in lamports (1 SOL = 1,000,000,000 lamports).
          example: 5000000
        h1_year:
          type: integer
          description: UTC year of the insertion block timestamp.
          example: 2026
        h1_month:
          type: integer
          minimum: 1
          maximum: 12
          description: UTC month (1-12).
          example: 2
        h1_day:
          type: integer
          minimum: 1
          maximum: 31
          description: UTC day (1-31).
          example: 25
        h1_hour:
          type: integer
          minimum: 0
          maximum: 23
          description: UTC hour (0-23).
          example: 12
        h1_minute:
          type: integer
          minimum: 0
          maximum: 59
          description: UTC minute (0-59).
          example: 0
        h1_second:
          type: integer
          minimum: 0
          maximum: 59
          description: UTC second (0-59).
          example: 0
        h1_purpose:
          type: integer
          description: Smart-program-provable domain tag (`u32`).
          example: 1
        h1_circuit_provable_hash:
          type: string
          format: byte
          description: >-
            Raw 32-byte `Poseidon(circuit_provable_inputs)`, little-endian
            (Protobuf `bytes`).
        h1_smart_program_provable_hash:
          type: string
          format: byte
          description: >-
            Raw 32-byte `Poseidon([h1_purpose])`, little-endian (Protobuf
            `bytes`).
        h1_hash:
          type: string
          format: byte
          description: >
            Raw 32-byte `Poseidon([h1_circuit_provable_hash,
            h1_smart_program_provable_hash])`,

            little-endian (Protobuf `bytes`).
        h2_hash:
          type: string
          format: byte
          description: >-
            Raw 32-byte private commitment hash, little-endian (Protobuf
            `bytes`).
        aes_encrypted_data:
          type: string
          format: byte
          description: |
            Raw 96-byte AES-256-GCM encrypted UTXO payload (Protobuf `bytes`):
            - Bytes 0-11: 12-byte random nonce
            - Bytes 12-79: 68-byte ciphertext
            - Bytes 80-95: 16-byte authentication tag
        depositor_x25519_public_key:
          type: string
          format: byte
          description: |
            Raw 32-byte ephemeral X25519 public key. Used to derive the shared
            AES-256-GCM key for decrypting `aes_encrypted_data` via X25519 DH
            with the network's static private key (Protobuf `bytes`).
        timestamp:
          type: integer
          format: int64
          description: Unix block timestamp in seconds (`0` when unavailable).
          example: 1735689600
        slot:
          type: integer
          format: int64
          description: Solana slot number of the confirming block.
          example: 350000000
        event_type:
          type: string
          description: '`"deposit"` or `"callback"` (see `EventType`).'
          example: deposit
    UtxoColumns:
      type: object
      description: >
        Protobuf `UtxoColumns` sub-message used inside `UtxoColumnarResponse`.


        Stores all UTXO fields as **parallel arrays** -- one repeated field per
        column.

        The `i`-th element of every array corresponds to the `i`-th UTXO in the
        page.


        Binary fields (`final_commitment`, hash fields, `aes_encrypted_data`,

        `depositor_x25519_public_key`) are `repeated bytes` in the Protobuf
        encoding.

        The `h1_version` and `h1_commitment_index` fields are `repeated bytes`
        where

        each element is the **16-byte little-endian** encoding of the original
        `u128`.
      properties:
        absolute_index:
          type: array
          items:
            type: integer
            format: int64
          description: Absolute indices for all rows in this page.
        tree_index:
          type: array
          items:
            type: integer
            format: int64
        insertion_index:
          type: array
          items:
            type: integer
            format: int64
        final_commitment:
          type: array
          items:
            type: string
            format: byte
          description: 32-byte `Poseidon(h1, h2)` for each row.
        h1_version:
          type: array
          items:
            type: string
            format: byte
          description: 16-byte little-endian `u128` protocol version per row.
        h1_commitment_index:
          type: array
          items:
            type: string
            format: byte
          description: 16-byte little-endian `u128` commitment index per row.
        h1_sender_address:
          type: array
          items:
            type: string
            format: byte
        h1_mint_address:
          type: array
          items:
            type: string
            format: byte
        h1_relayer_fixed_sol_fees:
          type: array
          items:
            type: integer
            format: int64
        h1_year:
          type: array
          items:
            type: integer
        h1_month:
          type: array
          items:
            type: integer
        h1_day:
          type: array
          items:
            type: integer
        h1_hour:
          type: array
          items:
            type: integer
        h1_minute:
          type: array
          items:
            type: integer
        h1_second:
          type: array
          items:
            type: integer
        h1_purpose:
          type: array
          items:
            type: integer
        h1_circuit_provable_hash:
          type: array
          items:
            type: string
            format: byte
        h1_smart_program_provable_hash:
          type: array
          items:
            type: string
            format: byte
        h1_hash:
          type: array
          items:
            type: string
            format: byte
        h2_hash:
          type: array
          items:
            type: string
            format: byte
        aes_encrypted_data:
          type: array
          items:
            type: string
            format: byte
          description: 96-byte AES-GCM payload per row.
        depositor_x25519_public_key:
          type: array
          items:
            type: string
            format: byte
        timestamp:
          type: array
          items:
            type: integer
            format: int64
        slot:
          type: array
          items:
            type: integer
            format: int64
        event_type:
          type: array
          items:
            type: string
          description: '`"deposit"` or `"callback"` per row.'

````