# User asset balances

Source: https://docs.settlemint.com/docs/api-reference/tokens/user-asset-balances
List the authenticated participant's token holdings through the DALP API, aggregated across their linked wallets, with balances, base-currency value, and yield denomination details.



Call this route to retrieve the authenticated participant's token holdings.
Results are aggregated across all linked wallets, so each row represents one token
position rather than one address. The response includes total, frozen, and available
balances alongside a resolved base-currency value and a per-wallet breakdown for audit.

The route reads indexed balance state. When you receive an empty `data` array,
the participant holds no tracked assets in the active system; the data is not
missing.

## Endpoint [#endpoint]

```text
GET /api/v2/user-asset-balances
```

It returns a JSON:API paginated collection with `data`, `meta`, and
`links`. Each `data` item is one aggregated token balance for the participant.

```bash
curl --globoff --request GET \
  "$DALP_API_URL/api/v2/user-asset-balances?page[limit]=50&sort=-balance" \
  --header "X-Api-Key: $DALP_API_TOKEN"
```

## Holder scope and wallet aggregation [#holder-scope-and-wallet-aggregation]

Balances are calculated for the authenticated **participant**, not for a single
address. A participant can hold the same token through more than one linked
wallet, typically a signing account (EOA) and a smart wallet under account
abstraction. By default the endpoint aggregates each token's balance across the
participant's full set of linked wallets in the active system, so an
account-abstraction user sees one combined balance per token without your
integration fetching and summing each address separately.

Each row also includes a `byWallet` array that breaks the aggregate balance down
per wallet, so you can show both the combined total and the per-wallet split.

The response is scoped to the active system from your request context. If a
participant holds assets in more than one DALP system, each system's data
covers only that system's rows.

## Read another participant's holdings [#read-another-participants-holdings]

Send `filter[wallet]=0x…` to scope the response to a specific wallet instead of the
authenticated participant's own holdings. The platform honors the override for the
participant reading their own wallet, for platform admins reading any wallet, and
for active-organization user readers when the target wallet belongs to a user in
the caller's current organization. An organization user reader requesting a wallet
outside their organization is rejected with `FORBIDDEN`.

An honored override that resolves to a participant expands to that participant's
full linked wallet set, so the response stays an aggregate-holdings view rather
than a single-address view. A platform admin requesting a wallet that is not
attached to any participant reads that single wallet only. The Console uses this
pattern to show another user's holdings on a participant detail workspace
without requiring platform admin access.

## Query parameters [#query-parameters]

The endpoint uses the canonical collection query parameters.

| Parameter                | Use it for                                                                             |
| ------------------------ | -------------------------------------------------------------------------------------- |
| `page[limit]`            | Page size. Defaults to 50, with a maximum of 200.                                      |
| `page[offset]`           | Number of rows to skip for pagination.                                                 |
| `sort`                   | Sort order. Defaults to `-balance` (largest balance first).                            |
| `filter[q]`              | Global search across the token name and symbol.                                        |
| `filter[wallet]`         | Gated wallet override described above.                                                 |
| `filter[<field>]`        | Filter by `tokenAddress`, `tokenName`, `tokenSymbol`, or `tokenDecimals`.              |
| `filter[metadata.<key>]` | Filter by a metadata key declared on the token's asset-type template.                  |
| `groupBy`                | Group results by a bucketable metadata key and return per-group summaries (see below). |

`sort` accepts `balance`, `tokenAddress`, `tokenName`, and `tokenSymbol`. Prefix a
field with `-` for descending order. `tokenDecimals` can be filtered but not
sorted.

### Group by a metadata key [#group-by-a-metadata-key]

Send `groupBy=<key>` to group the participant's filtered holdings by a bucketable
metadata key declared on the token's asset-type template. The key must be declared
and bucketable, otherwise the platform rejects the request. When you set `groupBy`,
the response `meta` block adds a `groups` array of per-group summaries and a
`groupBy` object naming the active axis and its display label. A returned row
carries a `metadataValues` object holding the grouped key's value only when the
token has a value for that key; rows without a value for the grouped key omit the
field.

## Response shape [#response-shape]

Each `data` item represents one token the participant holds. Fields are described after the example.

```json
{
  "data": [
    {
      "id": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
      "value": "1.000000000000000000",
      "frozen": "0.000000000000000000",
      "available": "1.000000000000000000",
      "valueInBaseCurrency": "1000.00",
      "priceInBaseCurrencyReliable": true,
      "token": {
        "id": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
        "name": "Bond Token",
        "symbol": "BOND",
        "type": "bond",
        "isExternal": false,
        "decimals": 18,
        "totalSupply": "1000000",
        "bond": { "isMatured": false },
        "yield": {
          "schedule": {
            "id": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
            "denominationAsset": {
              "id": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
              "symbol": "USDC",
              "decimals": 6
            }
          }
        }
      },
      "byWallet": [
        {
          "wallet": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
          "value": "1.000000000000000000",
          "frozen": "0.000000000000000000",
          "available": "1.000000000000000000"
        }
      ]
    }
  ],
  "meta": {
    "total": 1,
    "facets": {}
  },
  "links": {
    "self": "/v2/user-asset-balances?page[limit]=50&page[offset]=0",
    "first": "/v2/user-asset-balances?page[limit]=50&page[offset]=0",
    "prev": null,
    "next": null,
    "last": "/v2/user-asset-balances?page[limit]=50&page[offset]=0"
  }
}
```

Each item includes:

* `id`: the token contract address for the aggregated balance row.
* `value`, `frozen`, `available`: the total, frozen, and available balance,
  adjusted by the token's `decimals` and returned as decimal strings.
* `valueInBaseCurrency`: the balance multiplied by the token's resolved price,
  expressed in the organization's base currency. The field is `null` when no price
  path is available for the token.
* `priceInBaseCurrencyReliable`: `false` when no price path is available, in which
  case `valueInBaseCurrency` is also `null`, or when a price is returned but a
  conversion hop fell back to a stale rate. When a value is present and this flag
  is `false`, treat the value with lower confidence.
* `token`: the token's name, symbol, type, decimals, total supply, and feature
  details such as bond maturity and yield.
* `byWallet`: the per-wallet breakdown of the aggregate balance, with each
  wallet's `value`, `frozen`, and `available` returned as decimal strings
  adjusted by the token's `decimals`, matching the aggregate row.

The `meta` block includes `total`, the count of distinct tokens matching the
request, and `facets`, the available metadata facet axes for the result. When a
request sets `groupBy`, `meta` also includes `groups` and `groupBy`.

## Yield denomination details [#yield-denomination-details]

For a token with a yield schedule, `token.yield.schedule.denominationAsset`
identifies the asset the schedule pays in, with its `symbol` and `decimals`. The
platform resolves that token's metadata by chain and
address, so a 6-decimal denomination asset returns `"decimals": 6` even when that
asset sits outside the participant's active system scope. Use the reported
`decimals` to convert denomination amounts rather than assuming 18.

When the schedule records a denomination asset address but its metadata is not
found, `denominationAsset.id` keeps that denomination asset address while `symbol`
and `decimals` fall back to `UNKNOWN` and 18. When the schedule has no recorded
denomination asset at all, `denominationAsset.id` is the schedule address with the
same `UNKNOWN`/18 fallback.

## Errors [#errors]

| Condition                                                             | Result         |
| --------------------------------------------------------------------- | -------------- |
| The participant has no wallet on file in the active system.           | `UNAUTHORIZED` |
| A `filter[wallet]` override targets a wallet the caller may not read. | `FORBIDDEN`    |

See the [platform API error reference](/docs/api-reference/errors/platform-api-error-reference)
for the full error contract.

## Related [#related]

* [Portfolio statistics](/docs/api-reference/tokens/portfolio-statistics) for the participant's aggregate value time series and asset-type breakdown.
* [Token holders and transfers](/docs/api-reference/tokens/token-holders-transfers) for per-token holder balances and transfer operations.
* [Getting started with API integration](/docs/api-reference/reference/getting-started)
