DEVELOPER DOCUMENTATION / GET STARTED

From zero to signal.

Make your first request in a few lines of code.

Base URL: https://api.fomo-api.com

01 Create an API key

Open API keys in your dashboard and create a key for your application. Copy the secret immediately — it is shown only once. Demo keys do not authenticate real requests.

02 Authenticate your requests

Send your key in the Authorization header. Keep it on your server, outside browser bundles and version control.

Authorization: Bearer <API_KEY>

03 Get the leaderboard

GET /v1/leaderboard?window=30d

Supported windows: 24h, 7d, and 30d. Use limit and cursor for pagination. This endpoint is public — no key required — but the row count depends on how you call it:

CallerRows per request
No Authorization header10
Free plan key20
Starter, Pro, Growth, Enterprisethe full top 150 (up to 200)

Asking for more than your cap is not an error — the response is still 200 and the rows are clamped, because refusing would break every caller already passing a larger limit. Every response carries a limits block saying which tier you are on, what the cap is, what you asked for, whether it was clamped, and where to upgrade. A request with an invalid or expired key is rejected with 401, not served as public.

The board parameter selects which question the ranking answers. The two boards measure different things, so the same trader can legitimately appear in a very different place on each. Pick deliberately.

fomo-parity — default

GET /v1/leaderboard?window=30dBETA — SHAPE AND NUMBERS MAY CHANGE

Ranks traders (a person, summed across every wallet we have linked to them) across all supported chains — Solana, Base, Ethereum, and BNB. This is what you get when you omit board, and passing board=fomo-parity returns exactly the same thing.

It has two sources, and it tells you which one you got. When FOMO’s own published figures for the window were captured less than two hours ago, this board serves those. When they are older than that, it serves our own computed numbers instead. Every response carries source — "fomo" or "computed" — and syncedAt, the moment the served figures were captured. The switch is whole-board: you never get a mix of rows from both, because two sources’ figures are not comparable and a ranking that interleaves them ranks nothing.

Rows are the same shape from either source: rank, traderId, handle, displayName, avatarUrl, pnlUsd, source, syncedAt. Fields that only one source can fill are present and null on the other — so realizedPnlUsd, unrealizedPnlUsd, networks and wallets are null on a FOMO row, and topHoldings, clan and allTimeRank are null on a computed one. Your parsing never has to branch on the source; your interpretation does.

What pnlUsd means depends on pnlBasis, not on you guessing. On FOMO’s figures it is always mark-to-market: realized plus unrealized, with positions still open valued at the current price. On our own numbers it is mark-to-market at 30d and realized at 24h and 7d — because the unrealized term is not scoped to the window, and at 24h it swamps everything else (on a measured board the top twenty were 93.4% unrealized at 24h against 27.1% at 30d). Ranking a “24h” board on that would rank positions opened weeks earlier. totalPnlUsd always carries realized-plus-unrealized if you want it.

Our figures sit beside theirs, always. realizedPnlUsd, unrealizedPnlUsd, volumeUsd and trades are always ours, computed over 30 days, in both modes — FOMO publishes one blended number we cannot split, so these are ours or they are nothing. computedPnlUsd is our total on that same basis, and the three reconcile exactly: realizedPnlUsd + unrealizedPnlUsd === computedPnlUsd. Because pnlUsd is the current source’s figure for the requested window, it does not reconcile with that split on a FOMO row, and is not meant to. returnPct and unrealizedSharePct are computed against computedPnlUsd, not pnlUsd.

fomoRatio is ours over theirs, and divergesFromFomo is true when they disagree by more than 1.5× in either direction. reportedBy and sourceField name where pnlUsd came from.

FOMO’s own counters keep FOMO’s names, and they are lifetime figures. fomoLifetimeVolumeUsd counts buys and sells over all time; fomoNumTrades and fomoSwapCount are two different lifetime trade counts of theirs, and our trades is a third definition. Do not compare them. allTimePnlUsd and allTimeRank come from FOMO’s badge and are all-time, not this window — they can read lower than a window figure, which is not a bug, and they are never the ranking key. Identity and these counters are remembered from the last capture that mentioned the trader, so they survive FOMO going quiet; fomoProfileSyncedAt tells you how old that block is, independently of syncedAt.

wallets are our verified links, never anything from a FOMO payload; walletLinkPending distinguishes “queued for linking” from “none”. In topHoldings, lifetimePnlUsd (and its older spelling pnlUsd) is gain since the position was opened, not gain inside the window.

Older field names — netUsd, realizedUsd, unrealizedUsd, totalPnlUsd and reportedPnlUsd — still carry the same values, but are deprecated and will be removed on 2026-11-27. Use pnlUsd, realizedPnlUsd and unrealizedPnlUsd.

Why this is beta. On our own numbers, a row depends on having a current price for every token a trader still holds, and our price coverage on the long tail of EVM tokens is incomplete — read lowCoverage before trusting a row. On FOMO’s figures, we did not compute the number and cannot audit it; it is published as reported, and every such response says so in attribution. Treat this board as indicative rather than settled, and do not build a billing or settlement flow on it.

solana

GET /v1/leaderboard?window=24h&board=solana

Ranks wallets by realized PnL on Solana: profit actually locked in by selling, matched buy-to-sell in first-in-first-out order. It deliberately claims nothing about a position you still hold, and nothing it cannot trace a purchase for — every row carries a coveragePct telling you how much of its cost basis we could account for, and pnlStatus telling you whether that was enough to call the number complete. This is the conservative, auditable board. It is always our own numbers and never switches source.

Results contain rank, address, realizedPnlUsd, returnPct, volumeUsd, trades, coveragePct, and pnlStatus. When a wallet has a verified linked identity, the row also carries displayName, handle, avatarUrl, and identityConfidence — all four are null when no identity is linked yet. Rows are keyed by address, not traderId: this is a different shape from fomo-parity, not a different view of it.

This board only lists wallets whose window PnL is complete at or above the coverage floor, so a page can end with hasMore: false before you reach limit rows — that is the full ranked set for that window, not a truncated page. fomo-parity applies no such floor, so it returns rows this board would have withheld.

It was called realized-pnl-solana. That spelling still works and returns this same board — permanently, not on a deprecation clock. Responses report board: "solana" either way. The same realized figures are also available per wallet on /v1/wallet/:address.

Common to both boards

Every response echoes the board it served and a top-level capturedAt, the snapshot update time — these are precomputed snapshots, not live queries, so two calls seconds apart return identical data. Metrics may be null, and null never means zero — it means we could not compute that figure to our own standard, and treating it as 0 will quietly corrupt any aggregate you build on it. Each leaderboard request counts as one unit against your monthly allowance, regardless of limit or board.

04 Look closer at a wallet

GET /v1/wallet/:address

Pass a Solana wallet address to retrieve its performance over 30 days. A wallet ranked on the solana board returns its board row. A wallet we hold figures for but did not rank returns its own figures with rank: null and a rankReason:

  • below_coverage_threshold — we could not attribute cost basis to enough of its sells to rank it; check coveragePct and pnlStatus before relying on realizedPnlUsd.
  • no_realized_pnl — no closed positions in the window.
  • trader_not_tracked — the wallet isn't linked to a trader on our tracked roster.
  • not_on_board_at_snapshot — it qualifies but was not ranked when the board was last built; it will be on the next one.

updatedAt is when the figures were computed. A 404 means we hold no figures for the wallet at all.

curl "https://api.fomo-api.com/v1/wallet/7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU" \
  -H "Authorization: Bearer <API_KEY>"

05 Get a wallet's individual trades

GET /v1/wallet/:address/trades

The trade-level feed behind a wallet's aggregate stats: every individual swap, newest first. Use limit (1–200, default 50) and offset for pagination.

curl "https://api.fomo-api.com/v1/wallet/7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU/trades?limit=50" \
  -H "Authorization: Bearer <API_KEY>"

Each entry contains txHash, blockTime, tokenIn / tokenOut (each with chain, address, and raw amount), venue, and source. The top-level total is the wallet's full trade count, independent of the current page.

06 Check plans & limits

GET /v1/plans

Public and unauthenticated. Returns the current pricing plans — id, name, prices (per currency: USD and INR), calls (monthly quota), rateLimit (requests per minute), description, and features — plus the passes (the one-time 30-day passes for Starter, Pro and Growth) and top-level currencies, usageUnit, and periodResets. This is the source of truth for quota and rate-limit numbers; use it instead of hardcoding plan limits.

Errors & rate limits

Handle 401 for missing or invalid keys, 403 for unavailable plan features, 404 for unknown wallets, and 429 for rate or quota limits. Respect the Retry-After header. Server failures return 5xx; use bounded exponential backoff.

Data sources & attribution

Every USD figure this API returns — realizedPnlUsd, netUsd, volumeUsd, returnPct — is a token amount read from the chain multiplied by a token price. Prices come from a chain of third-party price providers queried in a fixed order; the first one that can price a token at the block time we need wins, with separate providers covering current Solana marks and current EVM marks. Which provider priced a given token is not currently exposed in the response.

Coverage indicates how much activity is represented in the calculation. Rankings are analytics, not investment advice.