GET /leaderboard/volume: Polymarket Volume Leaderboard
curl --request GET \
--url https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volumeimport requests
url = "https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume', 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://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"results": [
{
"rank": 123,
"trader": "<string>",
"username": {},
"avatar": {},
"bravado_user_id": {},
"volume_usdc": "<string>",
"volume_shares": "<string>",
"trades": 123,
"category": {},
"category_share": {},
"category_basis": "<string>"
}
],
"window": "<string>",
"sort": "<string>",
"order": "<string>",
"total": {},
"has_more": true,
"totals": {
"traders": 123,
"volume_usdc": "<string>",
"volume_shares": "<string>",
"trades": 123
}
}Trader Data API
GET /leaderboard/volume: Polymarket Volume Leaderboard
Returns traders ranked by USDC trading volume for the requested rolling window.
GET
/
trader-analytics
/
leaderboard
/
volume
GET /leaderboard/volume: Polymarket Volume Leaderboard
curl --request GET \
--url https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volumeimport requests
url = "https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume', 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://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"results": [
{
"rank": 123,
"trader": "<string>",
"username": {},
"avatar": {},
"bravado_user_id": {},
"volume_usdc": "<string>",
"volume_shares": "<string>",
"trades": 123,
"category": {},
"category_share": {},
"category_basis": "<string>"
}
],
"window": "<string>",
"sort": "<string>",
"order": "<string>",
"total": {},
"has_more": true,
"totals": {
"traders": 123,
"volume_usdc": "<string>",
"volume_shares": "<string>",
"trades": 123
}
}Sign each request with a fresh HMAC signature. The cURL and HTTP header values below are placeholders, not reusable credentials. For runnable signing code, use request signing examples. Python examples use the signed session from that page; Node.js examples use its
bravadoFetch helper.GET https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume
Query Parameters
string
default:"24h"
Rolling time window. One of
1h, 4h, 24h, 7d, 30d, 90d, 365d, all.integer
default:"50"
Number of traders to return. Maximum 500.
integer
default:"0"
Offset for pagination. See Pagination. Passing
order=asc is usually cheaper than a large offset — see the note below.string
default:"volume_usdc"
Ranking column:
volume_usdc (USDC notional), trades (fill count), or volume_shares (contracts traded). This board carries no PnL fields, so a PnL sort key from GET /leaderboard is rejected with 400.string
default:"desc"
desc or asc. order=asc reads the bottom of the board directly — e.g. the least-active traders — without walking pages backward from an offset you have to discover first.integer
default:"0"
Minimum trade count to be included in the candidate set. Note this board’s default is
0, while GET /leaderboard’s default is 5 — pass the same value to both endpoints to compare over the same set of traders.string
Filter: keep only wallets whose dominant category equals this value. One of
Politics, Crypto, Sports, Science, Tech, Entertainment, Earnings, Finance, Geopolitics, World, Elections, Weather, Other. This is not “rank within category X” — it narrows which wallets qualify for the board at all, then ranks the survivors normally. On day-grained windows (7d/30d/90d/365d/all) this matches the wallet’s dominance in that window; on sub-day windows (1h/4h/24h), which have no day-grained answer to give, it matches the wallet’s all-time dominant category instead (see category_basis below) — the filter works the same way on every board, just against an explicitly all-time question on sub-day ones. Returns 400 on a window the category backfill hasn’t reached yet (see category_basis below), and on any venue other than Polymarket.Response
array
Show VolumeLeaderboardRow fields
Show VolumeLeaderboardRow fields
integer
1-based rank.
string
Polygon wallet address.
string | null
Polymarket display name.
string | null
Avatar image URL.
string | null
Internal Bravado user identifier.
string
Total USDC notional traded.
string
Total shares traded.
integer
Trade events in the window.
string | null
The wallet’s dominant category (by volume). On a day-grained window (
7d/30d/90d/365d) this follows that board’s window — e.g. a wallet ranked on a 30d board because of one Elections bet reads Elections here, not an all-time label. On window=all and on sub-day boards (1h/4h/24h) it is the wallet’s all-time dominant category — sub-day boards have no day-grained answer to give, so rather than show nothing they show the wallet’s real all-time category, labelled distinctly (see category_basis). null when unknown; see category_basis. May legitimately be "Other" — that is a real classification (the catalogue’s explicit residual bucket), not a fake default.string | null
category’s share of the wallet’s own volume_usdc over whichever window category was computed on (the board’s own window, or all-time for window=all/sub-day boards) — a volume share, not a PnL share. Present only alongside category.string
Why
category is present or absent, and how it should be read: all_time (window=all, a real classification), all_time_fallback (1h/4h/24h — the SAME all-time classification as all_time, served because no day-grained answer exists at that grain; not the window’s own dominance), window_daily (7d/30d/90d/365d, a real classification for that window), no_classifiable_volume (the wallet has no CLOB-traded volume in a classified market — e.g. only splits/merges/redemptions; permanent), backfill_incomplete (the category rollup — or, for a sub-day board, the all-time coverage the fallback depends on — hasn’t reached this window yet; transient, clears on its own, no client change needed), or unsupported_venue.string
Echo of the window parameter used for the response.
string
Echo of the ranking column actually applied (default resolved).
string
Echo of the ranking direction actually applied (default resolved).
integer | null
Size of the candidate set after
min_trades — the number of rows a full page walk visits. null only if it could not be counted; never a fake 0.boolean
true while offset + results.length < total.object | null
Board-wide aggregate over the same candidate set as
total — for a stat-strip header, not for paging. null only if it could not be computed.Errors
| Status | When |
|---|---|
400 Bad Request | Invalid window, sort, order, limit, offset, or category value, or category requested for a window/venue it isn’t available on yet |
401 Unauthorized | Missing or invalid HMAC credentials |
429 Too Many Requests | Rate limit exceeded, see Retry-After header |
Example
curl -G https://partner-api.bravadotrade.com/trader-analytics/leaderboard/volume \
-H "X-BRAVADO-API-KEY: $BRAVADO_API_KEY" \
-H "X-BRAVADO-TIMESTAMP: <unix-ms>" \
-H "X-BRAVADO-SIGNATURE: <signature-for-this-request>" \
-d window=30d \
-d sort=volume_usdc \
-d order=desc
{
"mode": "volume",
"window": "30d",
"sort": "volume_usdc",
"order": "desc",
"total": 354368,
"has_more": true,
"totals": {
"traders": 354368,
"volume_usdc": "4713238818.319375",
"volume_shares": "9321187808.414698",
"trades": 144097085
},
"results": [
{
"rank": 1,
"trader": "0xdef789...abc012",
"username": "volumeking",
"volume_usdc": "2145000.000000",
"volume_shares": "3980210.550000",
"trades": 4820
}
]
}
Reading the bottom of the board
Becausetotal is now on the response, finding the end of the board no longer requires a binary search over offset. If you need the worst-performing or least-active traders specifically, sort=trades&order=asc (or sort=volume_usdc&order=asc) reads them directly from the front of an ascending sort — which is meaningfully cheaper than a large offset against a descending one, since ClickHouse still has to produce every row before a large offset even though it only returns the page after it.
Related
GET /leaderboardfor PnL-ranked results.GET /traders/{address}for per-trader detail.- Guide: Build a PnL leaderboard.