Skip to content

A wallet's LP positions

GET
/chains/solana/lp/wallet/{address}
curl --request GET \
--url 'https://api.getchord.xyz/v1/chains/solana/lp/wallet/example?status=open&unit=usd&limit=100'

The wallet’s positions as owner (DLMM: the position’s owner, not an operator acting for it), most recently active first, with totals over every position of the status asked: deposited, withdrawn, claimed fees, realized PnL and win rate over positions seen open to close. Cached 15 seconds.

Liquidity on Solana from Chord’s own tape: adds, removes, fee claims, position opens and closes, decoded from the same blocks as the swaps. No key needed.

  • Venues. Meteora DLMM, Meteora DAMM v2, Raydium CLMM and PumpSwap. Orca Whirlpools, Raydium CPMM / v4 and Meteora dynamic pools are not read yet.
  • Since. since is when LP decoding started (2026-10-06 15:53 UTC); windows never start before it. A position opened earlier is partial: true and carries no PnL.
  • Fees are claimed fees. An LP’s fees appear when it claims them, so a window’s fees understate what the pool earned, and one claim can hold days of fees.
  • Positions. One row per position account (DLMM / DAMM v2 position, Raydium CLMM position NFT, PumpSwap LP token account), rebuilt from all its events. lower / upper are DLMM bin ids or Raydium CLMM ticks; null = full range. Realized PnL = withdrawn + fees claimed − deposited, only for a position seen from its open to its close with every amount priced. An open position’s current value is not in the events: none is given.
  • Amounts are whole tokens in the pool’s own order (mintA / mintB); USD is valued when the event happened. Each add / remove / claim is checked against the pool vaults’ balance changes in the same transaction (verified).
  • Addresses are base58 and case-sensitive, as on the other Solana routes.
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.

status
string
default: all
Allowed values: open closed all

Which positions.

unit
string
default: usd
Allowed values: usd native

native = the money fields of the answer in SOL: every deposit, withdrawal and claimed fee converted at the SOL price of its own minute, so a wallet that put SOL in and took the same SOL out reads flat whatever SOL did in dollars (win rate and expected value follow the unit). The fields keep their …Usd names; unit and unitSymbol in the answer say what they carry. 503 UNIT_NOT_READY while positions are being folded again; another value is 400 BAD_UNIT.

limit
integer
default: 100 >= 1 <= 200

Rows; totals cover every position.

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}$/
status
string
since

Unix time, seconds, UTC.

integer | null
positions
integer
open
integer
closed
integer
pools
integer
depositedUsd
number
withdrawnUsd
number
feesClaimedUsd
number
realizedPnlUsd
number | null
realizedPositions
integer
winRate

0–1.

number | null
evUsd

Mean result of a realized position.

number | null
avgAgeHours
number | null
avgDepositUsd
number | null
firstTs

Unix time, seconds, UTC.

integer | null
lastTs

Unix time, seconds, UTC.

integer | null
history

One row per day a position ended on, oldest first, whatever status was asked. Its sums are realizedPnlUsd and feesClaimedUsd of status=all.

Array<object>
object
day

YYYY-MM-DD, UTC

string
profitUsd

Result of the realized positions that ended on the day.

number
feesUsd

Fees claimed by the positions that ended, or were last touched, on the day.

number
positions
integer
rows
Array<object>

One Solana LP position.

object
position

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

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

meteora_dlmm · meteora_damm_v2 · raydium_clmm · pumpswap.

string
pool

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

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

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

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

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

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

Creator-chosen.

string | null
mintB

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

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

Creator-chosen.

string | null
lower

DLMM bin id or CLMM tick.

integer | null
upper
integer | null
status
string
Allowed values: open closed
openedAt

Unix time, seconds, UTC.

integer | null
closedAt

Unix time, seconds, UTC.

integer | null
firstEvent

Unix time, seconds, UTC.

integer
lastEvent

Unix time, seconds, UTC.

integer
events
integer
depositedA

Whole tokens.

number | null
depositedB
number | null
withdrawnA
number | null
withdrawnB
number | null
feesA

Claimed.

number | null
feesB

Claimed.

number | null
depositedUsd
number
withdrawnUsd
number
feesClaimedUsd
number
realizedPnlUsd

Withdrawn + fees − deposited; null unless closed, not partial and fully priced.

number | null
partial

The tape did not see the open (opened before since); PumpSwap: more came out than the tape saw going in.

boolean
unpricedEvents

Value events without a USD price.

integer
updatedAt

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

integer
Example
{
"chain": "solana",
"wallet": "GwBsj9GJdFrATQs1k9EYUyfaatKZDiViy8tkU9JP3TUL",
"status": "all",
"since": 1791301995,
"positions": 750,
"open": 10,
"closed": 740,
"pools": 26,
"depositedUsd": 2649179.5405913335,
"withdrawnUsd": 2647817.6755300546,
"feesClaimedUsd": 18015.87641073856,
"realizedPnlUsd": 3345.1307860846005,
"realizedPositions": 722,
"winRate": 0.5512465373961218,
"evUsd": 4.633145133081164,
"avgAgeHours": 2.460573222071869,
"avgDepositUsd": 3575.1410804201532,
"firstTs": 1790774387,
"lastTs": 1791825711,
"history": [
{
"day": "2026-09-30",
"profitUsd": 0,
"feesUsd": 71.65268316036983,
"positions": 2
},
{
"day": "2026-10-01",
"profitUsd": 0,
"feesUsd": 7.083795820757369,
"positions": 2
},
{
"day": "2026-10-04",
"profitUsd": 0,
"feesUsd": 38.751457795784674,
"positions": 2
}
],
"rows": [
{
"position": "69v9s6gQje3Rk8u3vwn8kSEAxX1BNciUJEhG5Vb2fcPA",
"dex": "meteora_dlmm",
"pool": "GgoFghiA6Ca7YNmG6dRxwKQWkZhRK8ND47EREz46arot",
"owner": "GwBsj9GJdFrATQs1k9EYUyfaatKZDiViy8tkU9JP3TUL",
"mintA": "WXMRyRZhsa19ety5erZhHg4N3xj3EVN92u94422teJp",
"symbolA": "XMR",
"mintB": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"symbolB": "USDC",
"lower": -7544,
"upper": -7544,
"status": "closed",
"openedAt": 1791825038,
"closedAt": 1791825711,
"firstEvent": 1791825038,
"lastEvent": 1791825711,
"events": 5,
"depositedA": 0,
"depositedB": 9871.870653,
"withdrawnA": 15.009532666305,
"withdrawnB": 1897.560215,
"feesA": 0.017992659416,
"feesB": 2.482098,
"depositedUsd": 9871.870653,
"withdrawnUsd": 9879.734769314513,
"feesClaimedUsd": 12.050720244798956,
"realizedPnlUsd": 19.91483655931188,
"partial": false,
"unpricedEvents": 0
},
{
"position": "BpHs9ZbEoCTrM2P5JKY3cgxWhUTeMMUMa41jWiUjwQ9w",
"dex": "meteora_dlmm",
"pool": "GgoFghiA6Ca7YNmG6dRxwKQWkZhRK8ND47EREz46arot",
"owner": "GwBsj9GJdFrATQs1k9EYUyfaatKZDiViy8tkU9JP3TUL",
"mintA": "WXMRyRZhsa19ety5erZhHg4N3xj3EVN92u94422teJp",
"symbolA": "XMR",
"mintB": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"symbolB": "USDC",
"lower": -7545,
"upper": -7545,
"status": "closed",
"openedAt": 1791824988,
"closedAt": 1791825034,
"firstEvent": 1791824988,
"lastEvent": 1791825034,
"events": 5,
"depositedA": 0,
"depositedB": 9871.839615,
"withdrawnA": 0,
"withdrawnB": 9871.405961,
"feesA": 0.000141564492,
"feesB": 0.464692,
"depositedUsd": 9871.839615,
"withdrawnUsd": 9871.405961,
"feesClaimedUsd": 0.5398261385532628,
"realizedPnlUsd": 0.10617213855221053,
"partial": false,
"unpricedEvents": 0
}
],
"updatedAt": 1791836517
}

BAD_ADDRESS / BAD_STATUS / BAD_LIMIT, 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"
}