List User Holdings
Returns the user's holdings: their purchases collapsed to one row per token. Each row carries the position at the root (total_quantity, total_amount, overall_profit, source) and the token it is in under token. Pending buys are left out, because a quantity that has not settled on chain is not owned yet. For the per-buy history, including buys still in progress, use List User Purchases.
A user who holds nothing gets an empty page, not a 404.
Required permission: purchase:view
Request
GET /v2/users/{user_id}/purchases/groups
Parameters
| Name | Type | In | Description |
|---|---|---|---|
user_id | string | path | Required. User ID |
page | integer | query | Required. Page number, starting at 1 |
per_page | integer | query | Required. Items per page, 1–100 |
is_for_secondary | boolean | query | Only tokens that are listed and open to the secondary market |
is_for_otc | boolean | query | Only tokens that are listed and open to OTC. When both is_for_secondary and is_for_otc are sent, is_for_otc wins |
is_for_external | boolean | query | Only external-market purchases (market_type = 2) |
Headers
| Name | Description |
|---|---|
Authorization | Required. Bearer <access_token> |
Example
curl --request GET \
--url '{{baseUrl}}/v2/users/680c02896d91ca0145cfeb81/purchases/groups?page=1&per_page=10' \
--header 'Authorization: Bearer <access_token>'
Response
{
"data": [
{
"token_id": "68ae06cfcccf4e8fc19362d1",
"total_quantity": 25,
"total_amount": "28",
"overall_profit": "0.5",
"source": "purchase",
"token": {
"name": "Sample Token",
"symbol": "Sample",
"image": "https://cdn.example.com/tokens/68ae06cfcccf4e8fc19362d1/cover.png",
"address": "0x4ecde4b1b0a8f7a5d5c1e0f1a2b3c4d5e6f78387",
"diamond_address": "0x730d22ae2267fc5b40520605868ddb48c29331a7",
"status": 6,
"category_id": "667e9251ca818a2138ed4885",
"price_symbol": "VUSD",
"is_external": false,
"is_open_to_secondary_market": true,
"is_open_to_otc": true,
"secondary_market": {
"min_sell_price": "1",
"max_sell_price": "1.5"
},
"rate_changes": {
"hourly": null,
"daily": {
"start_date": "2026-11-09T00:05:12Z",
"end_date": "2026-11-09T09:40:03Z",
"start_value": "1.1",
"end_value": "1.12",
"rate": "1.81",
"change_type": 1
},
"weekly": null,
"monthly": null,
"quarterly": null
}
}
}
],
"total": 1,
"page": 1,
"per_page": 10
}
Response Fields
| Field | Type | Description |
|---|---|---|
data[].token_id | string | Token the row is about; the key the rows are grouped by |
data[].total_quantity | integer | Quantity of the token the user still holds (bought minus sold) |
data[].total_amount | string | Sum of quantity × unit price over the user's purchases of the token |
data[].overall_profit | string | null | Value of the held quantity at the token's current price minus the net amount paid for it (purchases minus sales). Can be negative. null when the net amount paid is not positive |
data[].source | string | Always purchase on this endpoint (the OTC and secondary-market group listings send otc / secondary_market) |
data[].token.name | string | Display name of the token |
data[].token.symbol | string | The token's on-chain name (token_name) |
data[].token.image | string | URL of the token's default image |
data[].token.address | string | Token contract address |
data[].token.diamond_address | string | Diamond contract of the node that issued the token |
data[].token.status | integer | Token status: 0 none, 1 draft, 2 in progress, 3 error, 4 not listed, 5 delisted, 6 listed, 7 passive, 8 burn |
data[].token.category_id | string | Category ID |
data[].token.price_symbol | string | Symbol of the currency the token's value is quoted in |
data[].token.is_external | boolean | true for a token issued outside the platform (bought through a partner integration, no platform fee) |
data[].token.is_open_to_secondary_market | boolean | Whether the token may be listed on the secondary market |
data[].token.is_open_to_otc | boolean | Whether OTC offers may be made on the token |
data[].token.secondary_market | object | null | Sell-price band for secondary-market listings: min_sell_price, max_sell_price (decimal strings or null). null when the token has none |
data[].token.rate_changes | object | Price movement per window: hourly, daily, weekly, monthly, quarterly. Each is a rate-change object (see Get Token Rates) or null when there is no history in that window |
total | integer | Number of tokens the user has purchases of (pending buys excluded) |
page | integer | Requested page |
per_page | integer | Requested page size |
Errors
| Status | Code | Description |
|---|---|---|
| 400 | 10015 | Validation failed (page, per_page) — see details |
| 500 | 10000 | Unexpected server-side failure |
See Errors for the error format and common codes.