TL;DR — which PnL field do you actually want?
This endpoint returns two different PnL numbers that can look very different for the same wallet. Pick the right one for your use case:
Both numbers are correct — they measure different things. See the worked example below for the math.
Path parameters
string
required
The Polymarket wallet address (Safe proxy or EOA, normalized to lowercase).
Query parameters
string
default:"30d"
Convenience window preset. One of:
7d, 14d, 30d, 60d, 90d, 180d. Anchored to “now”. If you pass period, you don’t need from.string | number
Start of the window. Accepts
YYYY-MM-DD (UTC midnight) or unix seconds. Overrides period if both are passed.string | number
End of the window. Same format as
from. Defaults to current time when omitted.boolean
default:"false"
When
1 or true, response includes a trades array with one entry per fill (ts, side, price, shares, actual_usd, backtest_usd). Useful for transparency and debugging.Response fields
Understanding cashflow PnL vs realized PnL
The most common source of confusion with this endpoint is “why don’tactual_pnl_usdc and total_realized_pnl_usdc agree?” — they’re answering different questions.
Worked example. A wallet’s first 30 days:
actual_pnl_usdc = -$16— the wallet paid out $16 more USDC than it received over the 30 days.total_realized_pnl_usdc = +$17.20— actual trading profit on the 130 shares the wallet closed.- The wallet still HOLDS 70 shares (cost basis $32.20). Cashflow counts that as money “spent”. Realized ignores it.
cashflow_pnl + cost_basis_of_open_positions ≈ realized_pnl. In this example: -$16 + $32.20 = $16.20 ≈ $17.20 (small rounding from WAVG cost basis updates).
Which to use:
- For “did the wallet make money trading?” →
total_realized_pnl_usdc. This is what trading platforms typically call “PnL” and what users intuitively expect. - For “how much net cash flowed through this wallet?” →
actual_pnl_usdc. Useful for liquidity analysis and the slippage formula, but not what most people mean by “PnL”. - For copy-trading slippage analysis → use
slippage_*fields (which are derived from cashflow). The slippage formula needs apples-to-apples cashflow comparison; this is whyactual_pnl_usdcis defined as cashflow.
Example: default 30-day window
Request:200 OK):
total_realized_pnl_usdc — and the answer is no.
Example: 7-day window via preset
Request:200 OK):
Example: explicit date range
Request — score the window from April 15 to April 25 inclusive:200 OK):
Example: per-fill drill-down
Request:200 OK, truncated):
Errors
400 Invalid period:
401 No API key:
403 Free tier:
429 Rate limited:
Retry-After header (in seconds, rounded up) is also set on 429 responses. The rate limit is shared across all /v2/copy-pnl/* calls per API key — calling the endpoint with different wallets or different params still counts toward the same 1 req per 5 seconds budget.
Notes
- Wallet address is case-insensitive. Internally lowercased.
- Time precision: when
fromisYYYY-MM-DD, it resolves to that date at 00:00 UTC. Pass unix seconds for sub-day precision. - Settlement events (redemption, merge, split, neg_risk_conversion) are processed at face value on both
actual_pnlandbacktest_copy_pnl, so they cancel out inslippage_amountbut remain in the absolute PnL numbers. - High-volume wallets: the underlying walk is paginated by time bucket and runs in parallel. Wallets with up to ~1.6M fills in the window have been validated. Beyond that, pass a tighter window or expect
partial: true.

