Skip to content

One wallet's tokens and PnL

GET
/chains/solana/wallet/{address}
curl --request GET \
--url 'https://api.getchord.xyz/v1/chains/solana/wallet/example?days=7'

What a wallet bought and sold per token over the last days UTC days (today included), with an average-cost PnL: realized on the sold part, unrealized on what is still held at the current price. Up to 200 tokens, biggest first. Say how far back the numbers go when you show them.

  • Transfers are not seen: a token that arrived by transfer and was then sold counts as a sell without a buy. Such rows carry partial: true (counted in partialTokens) and their sells have no realized PnL.
  • heldAmount and heldValueUsd are bought minus sold inside the window, not the on-chain balance.
  • likelyBot = more than 3,000 trades or 300 tokens a day.

Chord’s own Solana tape, read-only. No key needed.

  • What it reads. The swap events of 11 venues: PumpSwap, the pump.fun bonding curve, Meteora DBC, Meteora DAMM v2, Meteora DLMM, Meteora pools (dynamic AMM v1), Raydium CLMM, Raydium CPMM, Raydium AMM v4, Raydium LaunchLab and Orca Whirlpool. Each swap is checked against the pool vaults’ balance changes in the same transaction.
  • What it does not read. Prop AMMs (SolFi, HumidiFi and the like) and order books. SOL/USDC and other major pairs therefore show far less volume than the whole market; the numbers are accurate for pump.fun, Meteora and Raydium style tokens. Transfers are not seen either: wallet PnL is average cost inside the window.
  • History. Live since 2026-10-03 12:01 UTC, plus a backfill of the days before. coverageSince on /chains/solana/overview says from when totals are complete: quote that field, not a date.
  • Addresses are base58 and case-sensitive. Never lower-case a mint or a wallet: a lower-cased mint is a different string, refused with 400 BAD_ADDRESS when it stops being base58 (an L becomes l) and answered 404 TOKEN_NOT_FOUND otherwise. Solana has no numeric chain id here: the path segment is the literal solana.
  • Units. Token amounts are whole tokens (decimals already applied), quoteAmount is whole units of the pool’s quote (SOL, USDC, USDT or the other token), prices and *Usd fields are US dollars. Timestamps, updatedAt included, are Unix seconds.
  • Names are untrusted. symbol, name and image are whatever the token’s creator wrote; many mints share a symbol and there are no wash or impostor flags. Identify a token by its mint.
  • Errors. 400 BAD_* for a bad parameter; 400 UNSUPPORTED_CHAIN if Solana is not public on the deployment and the request has no X-API-Key; 503 CHAIN_DATA_UNAVAILABLE when the Solana store cannot be read in time and 503 CHAIN_NOT_ENABLED when the lane is off: retry later, never read either as “no trades”.
address
required

Solana address, base58, case-sensitive. Never lower-case it.

string
/^[1-9A-HJ-NP-Za-km-z]{32,44}$/

Wallet address, base58, exactly as it appears on-chain.

days
integer
default: 7 >= 1 <= 45

Window in UTC days, today included.

A wallet the tape has never seen answers zeros and an empty positions.

Media typeapplication/json
object
chain
string
Allowed value: solana
wallet

Solana address, base58, case-sensitive. Never lower-case it.

string
/^[1-9A-HJ-NP-Za-km-z]{32,44}$/
windowDays
integer
tokens
integer
trades
integer
volumeUsd
number
boughtUsd
number
soldUsd
number
realizedPnlUsd
number
unrealizedPnlUsd
number
heldValueUsd
number
winRate

Share of tokens with sells that closed in profit, 0–1.

number | null
partialTokens

Tokens with partial: true.

integer
likelyBot
boolean
positions

Biggest bought + sold first.

Array<object>

One token in a wallet’s window.

object
token

Solana address, base58, case-sensitive. Never lower-case it.

string
/^[1-9A-HJ-NP-Za-km-z]{32,44}$/
symbol
string | null
name
string | null
image
string | null
priceUsd

Current price on the main pool.

number | null
boughtUsd
number
soldUsd
number
boughtAmount

Whole tokens.

number
soldAmount

Whole tokens.

number
buys
integer
sells
integer
heldAmount

Bought minus sold inside the window, whole tokens (never below 0). Not the on-chain balance.

number
heldValueUsd
number | null
realizedPnlUsd

Matched amount × (average sell − average buy). Null when the window has sells but no buys.

number | null
unrealizedPnlUsd

Held amount × (price − average buy).

number | null
partial

Sold more than it bought inside the window: part of the position was bought before the window (or arrived by transfer), so those sells carry no cost basis.

boolean
lastDay

Unix time, seconds, UTC.

integer
updatedAt

Unix time, SECONDS, when the Solana box built this answer. Unlike the rest of the API (milliseconds).

integer
Example
{
"chain": "solana",
"wallet": "3QZv9xcDELwLqB8SggDJHfVhMTn5YhKtXMCaKUucutm3",
"windowDays": 7,
"tokens": 3,
"trades": 10,
"volumeUsd": 249.92409078731498,
"boughtUsd": 157.82642149850838,
"soldUsd": 92.09766928880659,
"realizedPnlUsd": 10.89172430885074,
"unrealizedPnlUsd": -13.521686548756673,
"heldValueUsd": 92.65951096979586,
"winRate": 1,
"partialTokens": 1,
"likelyBot": false,
"positions": [
{
"token": "7VertkgF9KLhxxJXHX6uaWuoYZTP9LdGj2bWmVXVpump",
"symbol": "Agency",
"name": "Agency",
"image": "https://ipfs.io/ipfs/bafybeicailrr3iobedoxprzs6evwq3nqxsezdhvxbhpseyhltfmufybxuq",
"priceUsd": 0.012298957291368744,
"boughtUsd": 139.35060978011185,
"soldUsd": 62.536948288806585,
"boughtAmount": 9685.829453,
"soldAmount": 3589.699624,
"buys": 5,
"sells": 2,
"heldAmount": 6096.129829,
"heldValueUsd": 74.97604040951005,
"realizedPnlUsd": 10.89172430885074,
"unrealizedPnlUsd": -12.72934539064596,
"partial": false,
"lastDay": 1791072000
},
{
"token": "So11111111111111111111111111111111111111112",
"symbol": "SOL",
"name": "Solana",
"image": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png",
"priceUsd": 120.9862,
"boughtUsd": 0,
"soldUsd": 29.560721,
"boughtAmount": 0,
"soldAmount": 0.247089203,
"buys": 0,
"sells": 1,
"heldAmount": 0,
"heldValueUsd": 0,
"realizedPnlUsd": null,
"unrealizedPnlUsd": 0,
"partial": true,
"lastDay": 1790985600
}
],
"updatedAt": 1791166532
}

BAD_ADDRESS / BAD_DAYS, or UNSUPPORTED_CHAIN (Solana is not public on this deployment and the request has no X-API-Key).

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
Example
{
"error": "INVALID_PARAMS",
"message": "amount must be an integer string in the token's smallest unit"
}

Over the per-minute limit (RATE_LIMIT_EXCEEDED). Read X-RateLimit-Reset and back off.

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
Example
{
"error": "INVALID_PARAMS",
"message": "amount must be an integer string in the token's smallest unit"
}

CHAIN_DATA_UNAVAILABLE (the Solana store did not answer in time) or CHAIN_NOT_ENABLED (the lane is off on this deployment). Retry later; do not treat it as an empty answer.

Media typeapplication/json

Every non-2xx body.

object
error
required

Stable machine code, e.g. INVALID_PARAMS, NOT_READY, RATE_LIMIT_EXCEEDED.

string
message

For humans.

string
statusCode

HTTP status, when included.

integer
Example
{
"error": "INVALID_PARAMS",
"message": "amount must be an integer string in the token's smallest unit"
}