Skip to content

Aggregation API: Batch Assets balances Endpoint #3

@sallymoc

Description

@sallymoc

Context

The wallet app currently fetches all asset holdings (tokens AND smart contract shares) for multiple addresses via POST https://api.qubic.li/Wallet/Assets. This qli endpoint is being deprecated and we need an aggregation endpoint to replace it.

The existing RPC live API has single-address endpoints for assets (GET /live/v1/assets/{identity}/owned, /possessed, /issued), but the wallet does not use them — it only uses the qli batch endpoint. The qli endpoint aggregates both owned and possessed data into a single flat response, covering all asset types:

  • Tokens (e.g., CFB, RANDOM, QFT, QWALLET, etc.) — fungible assets issued by various identities
  • Smart contract shares (e.g., QX shares, IPO shares) — shares in smart contracts

The wallet treats all of these the same way — they are displayed together in the Assets page, grouped by publicId + assetName + issuerIdentity.

Reference: The POST /aggregation/v1/getCurrentIpoBids endpoint is already live and follows the same request pattern ({ "identities": [...] }).


Current qli endpoint being replaced

POST https://api.qubic.li/Wallet/Assets
Content-Type: application/json
Authorization: Bearer <jwt-token>

["IDENTITY_1", "IDENTITY_2"]

Response (QubicAsset[]) — flat array, one entry per identity+asset+contract combination, including both tokens and SC shares:

[
  {
    "publicId": "BZBQFLLBNCXEMGLOBHUVFTLUPLVCPQUASSILFABOFFBCADQSSUPNWLZBQEXK",
    "contractIndex": 1,
    "assetName": "CFB",
    "contractName": "QX",
    "ownedAmount": 1000,
    "possessedAmount": 1000,
    "tick": 22451873,
    "reportingNodes": ["127.0.0.1"],
    "issuerIdentity": "CFBMEMZOIDEXQAUXYYSZIURADQLAPWPMNJXQSNVQZAHYVOPYUKKJBJUCTVJL"
  },
  {
    "publicId": "BZBQFLLBNCXEMGLOBHUVFTLUPLVCPQUASSILFABOFFBCADQSSUPNWLZBQEXK",
    "contractIndex": 1,
    "assetName": "QFT",
    "contractName": "QX",
    "ownedAmount": 50,
    "possessedAmount": 50,
    "tick": 22451873,
    "reportingNodes": ["127.0.0.1"],
    "issuerIdentity": "TFUYVBXYIYBVTEMJHAJGEJOOZHJBQFVQLTBBKMEHPEVIZFXZRPEYFUWGTIWG"
  },
  {
    "publicId": "BZBQFLLBNCXEMGLOBHUVFTLUPLVCPQUASSILFABOFFBCADQSSUPNWLZBQEXK",
    "contractIndex": 1,
    "assetName": "QWALLET",
    "contractName": "QX",
    "ownedAmount": 200,
    "possessedAmount": 200,
    "tick": 22451873,
    "reportingNodes": ["127.0.0.1"],
    "issuerIdentity": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFNQC"
  },
  {
    "publicId": "EPYWDREDNLHXOFYVGQUKPHJGOMPBSLDDGZDPKVQUMFXAIQYMZGEHPZTAAWON",
    "contractIndex": 1,
    "assetName": "RANDOM",
    "contractName": "QX",
    "ownedAmount": 10,
    "possessedAmount": 10,
    "tick": 22451870,
    "reportingNodes": ["127.0.0.1"],
    "issuerIdentity": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFNQC"
  }
]

Note: The qli endpoint pre-aggregates data that on the RPC side would require calling both /assets/{identity}/owned and /assets/{identity}/possessed separately and then merging the results. The ownedAmount and possessedAmount fields come from these two different RPC sources but qli returns them combined in a single entry.


What the wallet uses from this endpoint

Field Used How
publicId Yes Match assets to owning seed, grouping key
assetName Yes Display name, grouping key, asset selection (e.g., "CFB", "QFT", "RANDOM", "QWALLET")
issuerIdentity Yes Displayed in UI, used in transfer payload, part of grouping key
contractIndex Yes Smart contract lookup, determines if asset is transferable (only QX-managed assets can be transferred)
contractName Yes Displayed in UI
ownedAmount Yes Displayed amount, max transfer validation
possessedAmount Yes Displayed alongside owned amount (shown as "Owned / Possessed" in the assets table)
tick Yes Data freshness indicator
reportingNodes No Not used by the wallet

Requirements

  • Must return all asset types: tokens (CFB, QFT, RANDOM, QWALLET, etc.) and smart contract shares — the wallet does not distinguish between them
  • A single identity can have multiple assets (one entry per asset per contract)
  • Both ownedAmount and possessedAmount are needed — they come from different RPC sources (/owned vs /possessed) but should be returned together
  • No authentication should be required (public data)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    🚫 Blocked

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions