Skip to main content
A raw balance shows what a wallet holds right now, but it hides the cost paid to get there and ignores every trade already closed. A wallet PnL tracker answers the question a balance cannot: did this wallet make money, and on which tokens.

TL;DR

  • Snapshot net worth and plot the equity curve
  • Compute realized and unrealized profit and loss per token
  • Compare PnL across multiple wallets on a single token
Reference architecture for a wallet PnL tracker built on Birdeye Data wallet endpoints All requests share the base URL https://public-api.birdeye.so and authenticate with the X-API-KEY header. The snapshot endpoints are Solana only. The PnL endpoints also support twelve EVM chains, selected with the x-chain header.

The three stage pipeline

1

Snapshot net worth and plot the equity curve

The first screen shows two things: what the wallet is worth right now, and how that worth got there.Endpoint: GET /wallet/v2/current-net-worth, GET /wallet/v2/net-worth
total_value, each holding’s value, and balance come back as JSON strings, not numbers. Parse each to a number before any maths, or you concatenate text instead of summing. balance is the raw on chain amount while amount is already scaled down, so display amount rather than balance to avoid a holding inflated by a million times.
Add net-worth for the equity curve, which returns dated points with a precomputed change.
count caps at 90 points. For a longer curve, set time to the oldest timestamp you already hold and keep direction=back, stitching pages onto the front of the series. Unlike total_value on the snapshot call, net_worth here is already a number, not a string.
2

Compute realized and unrealized PnL per token

This is the engine of the tracker. One POST call returns both the whole wallet summary and the token by token breakdown.Endpoint: POST /wallet/v2/pnl/details
Three things trip up almost everyone. The payload has no success field, so guarding on response.success rejects a valid response. Win rate is not at summary.win_rate, it lives at summary.counts.win_rate. And pricing.current_price can be null for a token no longer priced, so guard before any unrealized figure that depends on it.
Render the table from pnl.realized_profit_usd, pnl.unrealized_usd, pnl.total_usd, and pnl.avg_profit_per_trade_usd per token. The wallet header mirrors that shape at summary.pnl.* and summary.unique_tokens, so one call fills both sections.
3

Compare wallets on a single token

The final stage flips the question: of everyone holding this token, who is up. Pass one mint and a list of wallets to build a holder leaderboard.Endpoint: GET /wallet/v2/pnl/multiple
The parameter names flip from Step 2: here it is token_address (singular) and wallets (plural), while pnl/details takes wallet (singular) and an optional token_addresses array. Send the wrong pair and the call rejects the request.
The results in data.data are an object keyed by wallet address, not an array. Use Object.entries(data.data) to get pairs, then sort by pnl.total_usd to rank holders. wallets caps at 50 addresses per call.

Watch your credit budget

A tracker that refreshes on every page view can run up calls quickly, and pnl/details is the heaviest call of the three. Endpoint: GET /utils/v1/credits
Cache the snapshot and PnL response for a wallet and serve it for a short window rather than recomputing on every keystroke or tab switch.

Before you ship

  • String fields total_value, value, and balance are parsed to numbers before maths.
  • Holdings display amount, not the raw balance.
  • pnl/details is read without a success guard, and win rate is taken from summary.counts.win_rate.
  • pnl/multiple results are read with Object.entries(data.data), then sorted by pnl.total_usd.
  • Responses are cached per wallet, with credits monitored as usage grows.

FAQ

The snapshot endpoints, current-net-worth and net-worth, are Solana only. The two PnL endpoints also support twelve EVM chains, selected with x-chain, so the PnL core travels beyond Solana even though the equity curve does not.
Realized PnL is profit locked in on tokens the wallet has already sold, at pnl.realized_profit_usd. Unrealized PnL is the paper gain or loss on tokens still held, at pnl.unrealized_usd. pnl.total_usd combines both.
Net worth and PnL change only when the wallet trades or prices move, so refreshing every few seconds wastes calls. Cache each wallet’s snapshot and PnL for a short window, refresh the equity curve less often than live price, and let the credits endpoint tell you when to widen those windows.
Net worth, an equity curve, per token PnL, and a multi wallet comparison: a raw balance turns into an actual track record.