curl --request GET \
--url https://data.gravia.trade/api/v1/users/trades/counterparties \
--header 'Authorization: <api-key>'import requests
url = "https://data.gravia.trade/api/v1/users/trades/counterparties"
headers = {"Authorization": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: '<api-key>'}};
fetch('https://data.gravia.trade/api/v1/users/trades/counterparties', 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://data.gravia.trade/api/v1/users/trades/counterparties",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: <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://data.gravia.trade/api/v1/users/trades/counterparties"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "<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://data.gravia.trade/api/v1/users/trades/counterparties")
.header("Authorization", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.gravia.trade/api/v1/users/trades/counterparties")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"user_address": "0x00000000000000000000000000000000000000ab",
"rows": [
{
"counterparty_address": "0x00000000000000000000000000000000000000cd",
"matched_usdc": 18420.75,
"conditions": 6,
"trade_count": 214,
"tx_count": 198,
"unique_order_hash_count": 203,
"counterparty_all_time_pnl": -12850.4,
"markouts": [
{
"horizon": "5s",
"pnl_usdc": 41.2,
"best_pnl_usdc": 96.4,
"worst_pnl_usdc": -18.7,
"evaluated_trades": 210,
"total_trades": 214,
"coverage": 0.9813
},
{
"horizon": "60s",
"pnl_usdc": 128.9,
"best_pnl_usdc": 260.1,
"worst_pnl_usdc": -74.3,
"evaluated_trades": 205,
"total_trades": 214,
"coverage": 0.9579
}
],
"terminal_markout": {
"pnl_usdc": 486.3,
"roi": 0.0264,
"evaluated_trades": 190,
"total_trades": 214,
"coverage": 0.8879
},
"first_trade_at": "2026-07-14T06:20:11.000Z",
"last_trade_at": "2026-07-15T05:47:52.000Z",
"you_maker_fills": 151,
"you_taker_fills": 63,
"them_maker_fills": 63,
"them_taker_fills": 151
}
],
"totals": {
"returned_counterparties": 1,
"matched_usdc": 18420.75
},
"window": {
"from": "2026-07-14T06:12:34.000Z",
"to": "2026-07-15T06:12:34.000Z"
},
"limit": 50,
"min_usdc": 100
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "rate_limit_exceeded",
"message": "rate limit exceeded",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}Get markouts grouped by counterparty
Resolves a wallet address or Polymarket username, structurally pairs matching fills, and groups the user’s trade-tape markouts by economic counterparty. A markout estimates hypothetical unrealized PnL at a fixed time after each fill, using the latest token trade-tape VWAP at or before the horizon. Positive PnL means the market moved in the user’s favor; buy and sell fills are adjusted in opposite directions. Markouts do not represent realized PnL and exclude fees.
For each horizon, pnl_usdc is the sum of evaluated fills’ point-in-time
markout PnL. best_pnl_usdc sums each fill’s most favorable PnL observed
between execution and that horizon, while worst_pnl_usdc sums each
fill’s least favorable PnL over the same interval. These are sums of
fill-level excursions, not the best or worst simultaneous value of the
combined portfolio and not confidence bounds. coverage is
evaluated_trades / total_trades; use it to distinguish a true zero
from an aggregate based on incomplete tape data or horizons that have
not elapsed.
terminal_markout aggregates resolved payout PnL where available and
reports its coverage. The default and maximum query window is seven
days.
curl --request GET \
--url https://data.gravia.trade/api/v1/users/trades/counterparties \
--header 'Authorization: <api-key>'import requests
url = "https://data.gravia.trade/api/v1/users/trades/counterparties"
headers = {"Authorization": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: '<api-key>'}};
fetch('https://data.gravia.trade/api/v1/users/trades/counterparties', 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://data.gravia.trade/api/v1/users/trades/counterparties",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: <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://data.gravia.trade/api/v1/users/trades/counterparties"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "<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://data.gravia.trade/api/v1/users/trades/counterparties")
.header("Authorization", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.gravia.trade/api/v1/users/trades/counterparties")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"user_address": "0x00000000000000000000000000000000000000ab",
"rows": [
{
"counterparty_address": "0x00000000000000000000000000000000000000cd",
"matched_usdc": 18420.75,
"conditions": 6,
"trade_count": 214,
"tx_count": 198,
"unique_order_hash_count": 203,
"counterparty_all_time_pnl": -12850.4,
"markouts": [
{
"horizon": "5s",
"pnl_usdc": 41.2,
"best_pnl_usdc": 96.4,
"worst_pnl_usdc": -18.7,
"evaluated_trades": 210,
"total_trades": 214,
"coverage": 0.9813
},
{
"horizon": "60s",
"pnl_usdc": 128.9,
"best_pnl_usdc": 260.1,
"worst_pnl_usdc": -74.3,
"evaluated_trades": 205,
"total_trades": 214,
"coverage": 0.9579
}
],
"terminal_markout": {
"pnl_usdc": 486.3,
"roi": 0.0264,
"evaluated_trades": 190,
"total_trades": 214,
"coverage": 0.8879
},
"first_trade_at": "2026-07-14T06:20:11.000Z",
"last_trade_at": "2026-07-15T05:47:52.000Z",
"you_maker_fills": 151,
"you_taker_fills": 63,
"them_maker_fills": 63,
"them_taker_fills": 151
}
],
"totals": {
"returned_counterparties": 1,
"matched_usdc": 18420.75
},
"window": {
"from": "2026-07-14T06:12:34.000Z",
"to": "2026-07-15T06:12:34.000Z"
},
"limit": 50,
"min_usdc": 100
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "rate_limit_exceeded",
"message": "rate limit exceeded",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}{
"error": {
"code": "invalid_request",
"message": "user is required",
"request_id": "01f6c90f31d24db3a25c7dba6ca071ee"
}
}Authorizations
Raw database-backed API key.
Query Parameters
A 20-byte 0x wallet address, @username, or bare Polymarket username.
1 - 255Inclusive RFC3339 window start. Defaults to seven days before to.
Inclusive RFC3339 window end. Defaults to the current time.
Restrict target-user fills by up to 20 comma-separated selectors:
market slugs, 0x-prefixed condition IDs, decimal outcome token IDs,
or category:<dotted-slug>. Mixed selectors are ORed. Exact market
identifiers do not expand to grouped markets; category parents
include descendants through inherited category membership.
5299Restrict target-user fills to one decimal outcome token ID.
^[0-9]+$Exclude counterparties below this matched USDC amount.
x >= 01 <= x <= 1000Response
Counterparty-level markout aggregates ordered by matched USDC.