Closed positions with metadata
curl --request GET \
--url https://api.polynode.dev/v2/wallets/{address}/closed-positions \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v2/wallets/{address}/closed-positions"
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/v2/wallets/{address}/closed-positions', 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/v2/wallets/{address}/closed-positions",
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/v2/wallets/{address}/closed-positions"
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/v2/wallets/{address}/closed-positions")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v2/wallets/{address}/closed-positions")
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{
"wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"count": 1,
"offset": 0,
"limit": 1,
"positions": [
{
"proxy_wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"asset": "34158857981196154020624191931838064546543114916900689904269497497174344049047",
"condition_id": "0x5346538cbfc880da50fe6b269a47e4f7cd8a38b2b120d85b1bc392d8cde6ced4",
"avg_price": 0.316481,
"total_bought": 654236.312162,
"realized_pnl": 447182.949852,
"cur_price": 1,
"title": "Nuggets vs. Warriors",
"slug": "nba-den-gsw-2026-02-22",
"icon": "https://polymarket-upload.s3.us-east-2.amazonaws.com/super+cool+basketball+in+red+and+blue+wow.png",
"event_slug": "nba-den-gsw-2026-02-22",
"outcome": "Warriors",
"outcome_index": 1,
"opposite_outcome": "Nuggets",
"opposite_asset": "107945275283604973510604597780969572155224468096168425689613528391046536169017",
"end_date": "2026-02-22T00:00:00Z",
"timestamp": 1771817602
}
]
}{
"error": "API key required. Get one at polynode.dev"
}{
"error": "Not found."
}Closed Positions
Paginated list of closed positions with full metadata and P&L.
GET
/
v2
/
wallets
/
{address}
/
closed-positions
Closed positions with metadata
curl --request GET \
--url https://api.polynode.dev/v2/wallets/{address}/closed-positions \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v2/wallets/{address}/closed-positions"
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/v2/wallets/{address}/closed-positions', 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/v2/wallets/{address}/closed-positions",
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/v2/wallets/{address}/closed-positions"
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/v2/wallets/{address}/closed-positions")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v2/wallets/{address}/closed-positions")
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{
"wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"count": 1,
"offset": 0,
"limit": 1,
"positions": [
{
"proxy_wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"asset": "34158857981196154020624191931838064546543114916900689904269497497174344049047",
"condition_id": "0x5346538cbfc880da50fe6b269a47e4f7cd8a38b2b120d85b1bc392d8cde6ced4",
"avg_price": 0.316481,
"total_bought": 654236.312162,
"realized_pnl": 447182.949852,
"cur_price": 1,
"title": "Nuggets vs. Warriors",
"slug": "nba-den-gsw-2026-02-22",
"icon": "https://polymarket-upload.s3.us-east-2.amazonaws.com/super+cool+basketball+in+red+and+blue+wow.png",
"event_slug": "nba-den-gsw-2026-02-22",
"outcome": "Warriors",
"outcome_index": 1,
"opposite_outcome": "Nuggets",
"opposite_asset": "107945275283604973510604597780969572155224468096168425689613528391046536169017",
"end_date": "2026-02-22T00:00:00Z",
"timestamp": 1771817602
}
]
}{
"error": "API key required. Get one at polynode.dev"
}{
"error": "Not found."
}Returns closed positions for a wallet with market metadata (title, outcome, slug) and realized P&L. Supports pagination and sorting.
Data source — read before you integrate. This endpoint uses Polymarket’s own
data-api.polymarket.com/closed-positions format and wraps it with pagination metadata. Row field names are Polymarket’s names preserved as-is — so you’ll see asset (not token_id), proxy_wallet, cur_price, title (not market). Coverage follows Polymarket’s closed-position dataset; positions missing there won’t appear here.For onchain truth with our own P&L calculations and consistent field naming across the rest of the API, use /v2/wallets/{address}/positions/onchain — that endpoint returns every position the wallet has ever held (open and closed), with token_id, size, realized_pnl, and unrealized_pnl in a shape consistent with the other /v2/onchain/* endpoints.Request
GET /v2/wallets/{address}/closed-positions
| Parameter | Type | Default | Description |
|---|---|---|---|
address | path | Wallet address (0x-prefixed) | |
limit | query | 10 | Results per page (max 50) |
offset | query | 0 | Pagination offset |
sortBy | query | TIMESTAMP | Sort field: REALIZEDPNL, AVGPRICE, PRICE, TITLE, TIMESTAMP |
sortDirection | query | DESC | ASC or DESC |
market | query | Filter by market slug | |
title | query | Filter by title substring |
Response
{
"wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"count": 3,
"offset": 0,
"limit": 3,
"positions": [
{
"proxy_wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"asset": "34158857981196154020624191931838064546543114916900689904269497497174344049047",
"condition_id": "0x5346538cbfc880da50fe6b269a47e4f7cd8a38b2b120d85b1bc392d8cde6ced4",
"avg_price": 0.316481,
"total_bought": 654236.312162,
"realized_pnl": 447182.949852,
"cur_price": 1,
"title": "Nuggets vs. Warriors",
"slug": "nba-den-gsw-2026-02-22",
"icon": "https://polymarket-upload.s3.us-east-2.amazonaws.com/super+cool+basketball+in+red+and+blue+wow.png",
"event_slug": "nba-den-gsw-2026-02-22",
"outcome": "Warriors",
"outcome_index": 1,
"opposite_outcome": "Nuggets",
"opposite_asset": "107945275283604973510604597780969572155224468096168425689613528391046536169017",
"end_date": "2026-02-22T00:00:00Z",
"timestamp": 1771817602
}
]
}
| Field | Description |
|---|---|
wallet | Queried wallet address (lowercased) |
count | Number of positions returned |
offset | Current pagination offset |
limit | Results per page |
proxy_wallet | Polymarket proxy wallet address |
asset | Token ID for this position (called token_id on the onchain positions endpoint) |
condition_id | CTF condition ID |
avg_price | Volume-weighted average entry price |
total_bought | Total tokens acquired |
realized_pnl | Profit or loss for this position in USDC |
cur_price | Current token price (1.0 for resolved winners, 0.0 for losers) |
title | Market title |
slug | Market slug |
icon | Market icon URL |
event_slug | Parent event slug |
outcome | Outcome name for this position |
outcome_index | Index of this outcome (0 or 1 for binary markets) |
opposite_outcome | Name of the other outcome |
opposite_asset | Token ID of the other outcome |
end_date | Market end date (ISO 8601) |
timestamp | Position timestamp (UNIX seconds) |
Example
# Top 5 closed positions by realized P&L
curl "https://api.polynode.dev/v2/wallets/0xbddf61af533ff524d27154e589d2d7a81510c684/closed-positions?limit=5&sortBy=REALIZEDPNL&sortDirection=DESC" \
-H "x-api-key: YOUR_KEY"
Authorizations
Path Parameters
Wallet address (0x-prefixed)
Query Parameters
Results per page (max 50)
Required range:
1 <= x <= 50Pagination offset
Required range:
x >= 0Sort field
Available options:
REALIZEDPNL, AVGPRICE, PRICE, TITLE, TIMESTAMP Sort direction
Available options:
ASC, DESC Filter by market slug
Filter by title substring
Response
Closed positions with metadata

