TUTORIAL

Solana wallet PnL API: get any wallet's PnL in one call

A practical quickstart for the Fomo Api Solana wallet PnL endpoint — curl, Node.js, and Python examples, what each field means, and how to handle coverage, nulls, and rate limits correctly.

Published September 22, 2026 · 7 min read

You have a Solana wallet address and you want its profit and loss — realized PnL, return, volume, trade count — as JSON, without running an indexer. That's GET /v1/wallet/:address. This post walks through the call in curl, Node.js, and Python, then the parts people get wrong.

1. Get a key

Sign in to the console, open API keys, create one. The Free plan (2,500 calls/month, 10 requests/minute) is enough to build against. Keep the key on your server — never in a browser bundle.

2. The call

curl

curl "https://api.fomo-api.com/v1/wallet/7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU" \
  -H "Authorization: Bearer $FOMO_API_KEY"

Node.js (fetch)

const res = await fetch(
  `https://api.fomo-api.com/v1/wallet/${address}`,
  { headers: { Authorization: `Bearer ${process.env.FOMO_API_KEY}` } },
);
if (res.status === 429) {
  const wait = Number(res.headers.get("retry-after") ?? 1);
  // back off `wait` seconds, then retry
}
const wallet = await res.json();
console.log(wallet.realizedPnlUsd, wallet.coveragePct);

Python (requests)

import os, requests

r = requests.get(
    f"https://api.fomo-api.com/v1/wallet/{address}",
    headers={"Authorization": f"Bearer {os.environ['FOMO_API_KEY']}"},
    timeout=10,
)
r.raise_for_status()
wallet = r.json()
print(wallet["realizedPnlUsd"], wallet["coveragePct"])

3. Reading the response

  • realizedPnlUsd — profit or loss from positions that were actually closed in the window, priced in USD, from FIFO cost basis. Open positions are not counted here.
  • returnPct — realized return relative to cost basis for the window.
  • volumeUsd, trades — how much and how often the wallet traded in the window.
  • coveragePct — the share of the wallet's activity that the numbers above are based on. Treat anything well below 100% as a partial picture and show it to your users.
  • pnlStatus — whether the window's PnL is complete or still being filled in.

The initial contract uses a 30-day window for the wallet endpoint. For 24h and 7d rankings across many wallets, use /v1/leaderboard?window=7d instead — it's one call regardless of row count, which is far cheaper than fanning out per wallet.

4. The three mistakes to avoid

  1. Treating null as 0. We return null when we can't compute a metric confidently. Render "—", not "$0.00".
  2. Ignoring coverage. A huge PnL at 30% coverage is a hint, not a fact. Surface coveragePct next to the number.
  3. Retrying 429s immediately. Respect Retry-After. The per-minute limit is per key and per plan; monthly quota headers (X-Quota-Remaining) tell you how much of the month is left.

5. Going deeper: individual trades

curl "https://api.fomo-api.com/v1/wallet/<address>/trades?limit=50" \
  -H "Authorization: Bearer $FOMO_API_KEY"

Every swap, newest first: txHash, blockTime, tokenIn/tokenOut with raw amounts, venue (where it executed) and source (where it originated). Paginate with limit and offset; total is the wallet's full count. This is the feed to build your own charts or verify our aggregate against.

Errors

401 missing or invalid key · 403 feature not on your plan · 404 unknown wallet · 429 rate or quota limit · 5xx our fault, back off exponentially and check status.

Full reference in the docs. If you're comparing providers first, see the pricing comparison.