Wallet P&L time series
curl --request GET \
--url https://api.polynode.dev/v3/wallets/{address}/pnl/events \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v3/wallets/{address}/pnl/events"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.polynode.dev/v3/wallets/{address}/pnl/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.polynode.dev/v3/wallets/{address}/pnl/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.polynode.dev/v3/wallets/{address}/pnl/events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.polynode.dev/v3/wallets/{address}/pnl/events")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v3/wallets/{address}/pnl/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"wallets": [
{
"wallet": "<string>",
"type": "eoa"
}
]
}Wallet P&L
Wallet P&L Time Series
Realized P&L bucketed by hour, day, week, or month — chart-ready time series for a wallet.
GET
/
v3
/
wallets
/
{address}
/
pnl
/
events
Wallet P&L time series
curl --request GET \
--url https://api.polynode.dev/v3/wallets/{address}/pnl/events \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v3/wallets/{address}/pnl/events"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.polynode.dev/v3/wallets/{address}/pnl/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.polynode.dev/v3/wallets/{address}/pnl/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.polynode.dev/v3/wallets/{address}/pnl/events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.polynode.dev/v3/wallets/{address}/pnl/events")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v3/wallets/{address}/pnl/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"wallets": [
{
"wallet": "<string>",
"type": "eoa"
}
]
}Returns wallet P&L buckets for charting. With
If
Buckets are summed per bucket across the combined wallets, and
period, after, or before, each row is a fixed time window (hour, day, week, or month). A running cumulative_pnl is included so the response can be plotted directly.
These standard spot P&L buckets exclude separately reported trader-paid
fees, rebates, and rewards. cumulative_pnl accumulates the returned P&L;
it is not an after-fee account return. See Wallet P&L accounting scope
and Fees Paid for the separate fee data.
Event-series mode is separate from the boundary-state calculation used by time-filtered GET /v3/wallets/{address}/pnl. Each bucket sums recorded weighted-average-cost realized-P&L event deltas. It is not a historical all-time-portfolio snapshot: holdings that are only bought and held can contribute 0, even when a resolved holding contributes profit to the current all-time P&L. Baseline corrections without an event timestamp are not placed into a bucket.
Without an explicit time filter, the endpoint returns a single all-time summary bucket that matches GET /v3/wallets/{address}/pnl.
In event-series mode, wins, losses, and events count realized P&L events in the selected window. In default summary mode, counts are position counts and the response includes count_type: "positions" and summary_bucket: true.
Rows at timestamp 0 or earlier are ignored in event-series mode, so explicit event windows start at Unix second 1.
Owner addresses. Pass an owner EOA as the wallet address and the response combines the EOA’s Polymarket wallets (Safe, proxy, deposit wallets) that have data for this endpoint. Passing a Safe, proxy or deposit wallet returns just that wallet, as before. Combined responses list the combined wallets in
wallets. See Owner addresses.Request
GET /v3/wallets/{address}/pnl/events
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
group | string | day | Bucket size: hour, day, week, month |
period | string | — | Shortcut for after: 1d, 7d, 30d, 1y |
after | integer | 1 | Start timestamp (Unix seconds, inclusive). Values below 1 are treated as 1. |
before | integer | now | End timestamp (Unix seconds, inclusive) |
limit | integer | 1000 | Max buckets returned, clamped to 1-1000 |
after and period are both set, after wins.
Examples
All-time summary bucket
curl "https://api.polynode.dev/v3/wallets/0xbddf61af533ff524d27154e589d2d7a81510c684/pnl/events"
{
"address": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"granularity": "day",
"bucket_count": 1,
"buckets": [
{
"bucket": 1779908613,
"realized_pnl": 29035964.931344,
"cumulative_pnl": 29035964.931344,
"gross_profit": 29818047.886063,
"gross_loss": -782082.954719,
"wins": 482,
"losses": 33,
"events": 1016,
"position_count": 1016,
"open_positions": 511,
"unrealized_pnl": -26917534.501466,
"total_pnl": 2118430.429878,
"total_volume": 177203290.120101
}
],
"total_realized_pnl": 29035964.931344,
"total_events": 1016,
"total_wins": 482,
"total_losses": 33,
"total_positions": 1016,
"open_positions": 511,
"unrealized_pnl": -26917534.501466,
"total_pnl": 2118430.429878,
"source": "wallet_summary",
"count_type": "positions",
"summary_bucket": true,
"elapsed_ms": 3
}
Daily P&L for the last 7 days
curl "https://api.polynode.dev/v3/wallets/0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1/pnl/events?period=7d&group=day"
{
"address": "0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1",
"granularity": "day",
"after": 1778478745,
"before": 1779083545,
"bucket_count": 3,
"buckets": [
{
"bucket": 1778889600,
"realized_pnl": 0.000525,
"cumulative_pnl": 0.000525,
"gross_profit": 0.000525,
"gross_loss": 0,
"wins": 1,
"losses": 0,
"events": 1
},
{
"bucket": 1778976000,
"realized_pnl": 611.069702,
"cumulative_pnl": 611.070227,
"gross_profit": 618.41811,
"gross_loss": -7.348408,
"wins": 23,
"losses": 3,
"events": 26
},
{
"bucket": 1779062400,
"realized_pnl": 11.774724,
"cumulative_pnl": 622.844951,
"gross_profit": 11.774724,
"gross_loss": 0,
"wins": 2,
"losses": 0,
"events": 2
}
],
"total_realized_pnl": 622.844951,
"total_events": 29,
"total_wins": 26,
"total_losses": 3,
"elapsed_ms": 4
}
Hourly P&L for an explicit window
curl "https://api.polynode.dev/v3/wallets/0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1/pnl/events?after=1778976000&before=1779062400&group=hour"
Weekly P&L for the last year
curl "https://api.polynode.dev/v3/wallets/0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1/pnl/events?period=1y&group=week"
Response fields
| Field | Type | Description |
|---|---|---|
address | string | The wallet address (lowercased) |
granularity | string | Resolved bucket size (hour, day, week, month) |
after | integer | Start of the window (Unix seconds, inclusive) |
before | integer | End of the window (Unix seconds, inclusive) |
bucket_count | integer | Number of buckets returned |
buckets | array | Time-series rows, ordered oldest → newest |
buckets[].bucket | integer | Bucket start timestamp (Unix seconds, UTC, truncated to bucket boundary) |
buckets[].realized_pnl | number | Weighted-average-cost realized P&L changes from indexed events in that bucket (USD) |
buckets[].cumulative_pnl | number | Running sum of realized_pnl over the returned series (USD) |
buckets[].gross_profit | number | Sum of winning events in that bucket (USD) |
buckets[].gross_loss | number | Sum of losing events in that bucket (USD, negative) |
buckets[].wins | integer | Count of winning events in that bucket |
buckets[].losses | integer | Count of losing events in that bucket |
buckets[].events | integer | Total P&L events in event-series mode; position count in default summary mode |
buckets[].position_count | integer | Position count. Present in default summary mode. |
buckets[].open_positions | integer | Open position count. Present in default summary mode. |
buckets[].unrealized_pnl | number | Current unrealized P&L. Present in default summary mode. |
buckets[].total_pnl | number | realized_pnl + unrealized_pnl. Present in default summary mode. |
buckets[].total_volume | number | Wallet volume from the summary source. Present in default summary mode. |
total_realized_pnl | number | Sum of event-realized realized_pnl across all returned buckets (USD); it is not expected to equal the current all-time P&L |
total_events | integer | Sum of events across all returned buckets |
total_wins | integer | Sum of wins across all returned buckets |
total_losses | integer | Sum of losses across all returned buckets |
source | string | Dataset label. Present in default summary mode. |
count_type | string | positions in default summary mode |
summary_bucket | boolean | true in default summary mode |
elapsed_ms | integer | Server-side query time in milliseconds |
Owner address fields
Present only when you pass an owner EOA. See Owner addresses.| Field | Type | Description |
|---|---|---|
wallets | array | The combined wallets, in a fixed order, each {wallet, type} with type one of eoa, safe, proxy, or deposit_wallet |
cumulative_pnl and the total_* fields cover the combined series. With period, after, or before, every wallet uses the same window, and address stays the address you passed. A wallet whose P&L is not loaded yet is left out of the combination and of wallets.
Errors
| HTTP | When |
|---|---|
400 | Invalid wallet address (must be 0x + 40 hex) |
400 | Invalid group value (must be hour, day, week, or month) |
400 | after greater than before |
Authorizations
Path Parameters
Wallet address, or an owner EOA to combine every Polymarket wallet it owns
Query Parameters
Bucket size
Available options:
hour, day, week, month Time window shortcut
Available options:
1d, 7d, 30d, 1y Unix timestamp lower bound. Values below 1 are clamped to 1.
Unix timestamp upper bound
Maximum bucket count, clamped to 1000
Required range:
1 <= x <= 1000Response
Wallet P&L buckets
Owner-address responses add the optional fields below. See the page for the full response.
Present only when you pass an owner EOA: the combined wallets, in a fixed order.
Show child attributes
Show child attributes

