Wallet portfolio API
GET/wallets/:chain/:address
A wallet's holdings now, read from the chain and valued in USD, its liquidity positions in the pools Aurelia indexes, each token with the wallet's position in it; and who the wallet is: its labels and its first funding.
Parameters
| Name | In | Type | Default | Allowed values |
|---|---|---|---|---|
chain | path | string | required | evm:56 (BSC), solana, evm:8453 (Base), evm:4663 (Robinhood Chain) or evm:1 (Ethereum) |
address | path | string | required | Wallet address (BSC) or account (Solana) |
limit | query | integer | 100 | 1–500 holdings |
Response
| Field | Type | Meaning |
|---|---|---|
chain, wallet, indexedSince | string, string, number | As in every wallet answer (see Wallets and PnL). |
labels | string[] | The wallet's labels. |
fundedBy | { address, amount, time, tx, labels } | null | Its first funding: who sent it its first BNB, ETH or SOL, how much (decimals applied), when and in which transaction, and the sender's labels. null when it cannot be established, with the reason in fundedByReason. |
fundedByReason | string | null | Why fundedBy is null. |
block, balancesAt | number | The block (Solana: slot) the balances reflect, and when they were read, unix ms. |
totalValueUsd | number | Sum of the counted holdings: priced, and not thin. |
pnl | { realizedUsd, unrealizedUsd, totalUsd } | All-time PnL of every non-quote position, held or not. Unknown unrealized PnL counts as 0. |
holdings[] | array | Token balances above 0 and liquidity positions: the counted ones by valueUsd, then the thin ones, then the unpriced ones. |
holdings[].kind | "token" | "lp" | A token balance, or a liquidity position in a pool Aurelia indexes. |
holdings[] (token) | object | token (address "native" for BNB, ETH or SOL), balance (decimals applied), priceUsd and valueUsd (null without a price), allocation (share of totalValueUsd, null for thin and unpriced holdings), thin (the token traded under $1,000 in 24 h, or no market backs its price, as for a null market cap: shown, not counted), position (as in wallet positions without token; null when it never traded it). |
holdings[] (lp) | object | protocol, pool, position (the position's id: an NFT or an account; null for a fungible LP token), lpToken ({ address, balance, supply, share } for a fungible one), tokens[] (each { token, amount, fees, locked, priceUsd, valueUsd }: what withdrawing all of it pays now, the uncollected fees (null where the protocol states none), and the part of the amount locked or vesting (Meteora DAMM v2; counted in the value)), range (concentrated liquidity and bins: lower, upper (exclusive), current ticks or bins, inRange, and the prices at them), valueUsd, feesUsd, allocation, thin. |
unpriced, count | number | Holdings without a price, and all holdings: limit cuts the list, never the totals. |
liquidity | { protocols, incomplete, notCovered, positionsIndexedSince, error } | What the liquidity read covered: the protocols read, those not read in full, those not covered and why, since when positions found through Aurelia's record of their transfers are known (unix ms; null while nothing is recorded), and the error when the chain could not be read (the portfolio then lists no position). |
Example
Captured 2026-09-28 18:03 UTC on a test instance, trimmed to 3 holdings.
curl -s -H 'Authorization: Bearer <key>' 'https://app.aurelia.build/api/wallets/evm:56/0x3304e22ddaa22bcdc5fca2269b418046ae7b566a?limit=3'
{
"chain": "evm:56",
"wallet": "0x3304e22ddaa22bcdc5fca2269b418046ae7b566a",
"indexedSince": 1790546261920,
"labels": [
"sniper",
"fresh"
],
"fundedBy": {
"address": "0x8894e0a0c962cb723c1976a4421c95949be2d4e3",
"amount": "0.25",
"time": 1790616461920,
"tx": "0x124aa51a8b73a7c373249b80ec4beb9fa4e80b4aa78a8bc73a64c781b3f2925d",
"labels": []
},
"fundedByReason": null,
"block": 1000748,
"balancesAt": 1790618266812,
"totalValueUsd": 214134,
"pnl": {
"realizedUsd": 59.5089770354906,
"unrealizedUsd": 6.776263578034403e-14,
"totalUsd": 59.50897703549067
},
"holdings": [
{
"kind": "token",
"token": {
"address": "0xa9fcda9bd321adeb7cbbbd30ef2dd0ed1d657777",
"symbol": "TAX",
"name": "Tax Token",
"decimals": 18
},
"balance": "21500000",
"priceUsd": 0.006,
"valueUsd": 129000,
"allocation": 0.6024265179747261,
"thin": false,
"position": {
"quote": false,
"trades": 22,
"buys": 12,
"sells": 10,
"unpricedTrades": 0,
"bought": "20118000",
"sold": "9800",
"open": "20108200",
"boughtUsd": 1008,
"soldUsd": 60,
"avgBuyPriceUsd": 0.00005010438413361169,
"avgSellPriceUsd": 0.006122448979591836,
"priceUsd": 0.006,
"priceAt": 1790618400000,
"realizedPnlUsd": 59.5089770354906,
"unrealizedPnlUsd": null,
"totalPnlUsd": 59.5089770354906,
"firstTradeAt": 1790546864920,
"lastTradeAt": 1790618578665
}
},
{
"kind": "lp",
"protocol": "pancakeswap-v2",
"pool": "0x702e6533e0182381606adbe3ccbb77f682ccc58b",
"position": null,
"lpToken": {
"address": "0x702e6533e0182381606adbe3ccbb77f682ccc58b",
"balance": "2000000000000000000000",
"supply": "100000000000000000000000",
"share": 0.02
},
"tokens": [
{
"token": {
"address": "0xa9fcda9bd321adeb7cbbbd30ef2dd0ed1d657777",
"symbol": "TAX",
"name": "Tax Token",
"decimals": 18
},
"amount": "14000000",
"fees": null,
"raw": {
"amount": "14000000000000000000000000",
"fees": null
},
"priceUsd": 0.006,
"valueUsd": 84000
},
{
"token": {
"address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"symbol": "WBNB",
"name": "Wrapped BNB",
"decimals": 18
},
"amount": "0.14",
"fees": null,
"raw": {
"amount": "140000000000000000",
"fees": null
},
"priceUsd": 600,
"valueUsd": 84.00000000000001
}
],
"range": null,
"valueUsd": 84084,
"feesUsd": null,
"allocation": 0.39267001036734006,
"thin": false
},
{
"kind": "token",
"token": {
"address": "native",
"symbol": "BNB",
"name": "BNB",
"decimals": 18
},
"balance": "1.25",
"priceUsd": 600,
"valueUsd": 750,
"allocation": 0.0035024797556670122,
"thin": false,
"position": null
}
],
"unpriced": 0,
"count": 6,
"liquidity": {
"protocols": [
"pancakeswap-v2",
"pancakeswap-v3",
"uniswap-v2",
"uniswap-v3"
],
"incomplete": [],
"notCovered": [
{
"protocol": "pancakeswap-infinity-cl",
"reason": "its positions are not enumerable per owner"
}
],
"error": null
}
}
Notes
- Balances are read from the chain: on BSC, BNB and every token the wallet sent, received or traded since indexing began; on Solana, SOL and every token account it owns. Cached 15 s per wallet, the answer 5 s.
502when the chain cannot be read,422for a BSC wallet that touched more than 2,000 tokens: a partial portfolio would be wrong, so neither sends one. - Liquidity positions: on BSC, the LP tokens among the balances (a V2-style pool is its own LP token) and the position NFTs of each enumerable position manager; on Solana, the token accounts whose mint is a position NFT or an LP mint. What withdrawing all of it pays now, read from one block or slot, rounded down as the program rounds (Raydium AMM v4 less the PnL it owes the protocol, CPMM less the fees held in its vaults); uncollected fees where the chain states them. An LP token a position stands for leaves the token holdings. Farm rewards, lending and staking are not covered.
- Positions nothing on chain lists by owner (Uniswap V4 and PancakeSwap Infinity NFTs on BSC, Meteora DLMM accounts on Solana) come from Aurelia's record of every transfer, creation and close since
positionsIndexedSince; each one is checked on chain (owner, liquidity) before it is shown. One whose last transfer came before that is not known, so these protocols are always inincomplete. BSC positions in pools whose hook can change what a withdrawal pays are left out. - The first funding is read on request and kept: for good once found. Solana: the wallet's oldest transactions; BSC: the first BNB transfer into it the index saw, confirmed by its balance and nonce being 0 the block before (the node must still keep that state). A request waits 3 s for it; a slower read goes on, and
fundedByReasonsays to ask again. - The thin rule keeps airdropped tokens out of the total: a price from a pool nobody trades is no value. BNB and SOL are priced as WBNB and WSOL.
- The balances channel sends this answer again whenever it changes.