Your users

Portfolio

Read the signed-in user's activity feed and the app leaderboard. Positions and orders are on Order lifecycle.

Activity is the signed-in user (x-app-id and Authorization: Bearer). The leaderboard is the app (x-app-id only).

Positions and orders are poll targets on Order lifecycle: GET /execution/positions and GET /execution/orders. The UI is Leaderboard.

For a profile screen, add user avatars. For backend reporting across all users in your app, use Partner admin with a server API key.

Activity

type is trade, withdrawal, bridge, deposit, user_op, or redeem.

SDK
const activity = await client.getUserActivity({ type: "trade", limit: 20 });

Full shape on Get user activity feed.

Leaderboard

metric is realizedPnl (default) or volume. rank is exact inside the top 100 and null after that. Pass exactly one of userId, externalId, username, or walletAddress to look up one user.

SDK
const board = await client.getLeaderboard({ metric: "realizedPnl", limit: 20 });

Full shape on Trader leaderboard.

One user's P&L over time

GET /leaderboard/series returns one user's daily orders, volume, spent, realizedPnl, and a running cumulativeRealizedPnl, oldest first. Pass exactly one of userId, externalId, username, or walletAddress. The default range is the last 30 days, and the maximum is 366. Days with no activity return 0. Unrealized P&L on open positions is not included.

SDK
const series = await client.getLeaderboardSeries({ externalId, from: "2026-09-01" });

Full shape on Trader leaderboard series.

One user's P&L between two timestamps

For a window shorter than a day, or not aligned to UTC days, pass from and to to GET /leaderboard as ISO-8601 timestamps with an offset (Z or ±hh:mm) instead of days, with exactly one of userId, externalId, username, or walletAddress, from your server with an x-app-api-key. You get that user's row over [from, to): orders, volume, spent, realizedPnl, wins, losses, and winRate, with rank: null. to defaults to now, the window is at most 366 days, and it can't be combined with categoryIds or venueEventIds. A timestamp without an offset is rejected; in a URL, encode a + offset as %2B. A window covering whole UTC days matches the day range.

Timestamp windows and hourly series need a server API key issued for this app, and return 403 without one or with another app's key. Narrowing a live window reveals each of a user's trades, so call this from your backend and never ship the key to a browser. Day ranges keep working with x-app-id alone.

SDK
// Server-side client created with createAggClient({ baseUrl, appId, apiKey })
const { data } = await client.getLeaderboard({
  externalId,
  from: "2026-09-01T09:00:00Z",
  to: "2026-09-01T17:00:00Z",
});
const realizedPnl = data[0]?.realizedPnl ?? 0;

Several users at once

Pass up to 20 userIds instead of a single-user lookup to get one row per user over the same window, ordered by metric. As with day ranges, users with no orders or settlements in the window are left out.

SDK
const { data } = await client.getLeaderboard({
  userIds: ["user-1", "user-2"],
  from: "2026-09-01T09:00:00Z",
  to: "2026-09-01T17:00:00Z",
});

One user's P&L per hour

GET /leaderboard/series with interval=hour and timestamp from/to returns one point per hour starting at from, over [from, to), at most 31 days (744 points). Each point has a start timestamp and the same fields as a daily point, and each hour matches a timestamp window over that hour. Hours without activity are 0. to defaults to now, the last point is shorter when to is not a whole number of hours after from, and it needs a single-user lookup and the same server API key.

SDK
const series = await client.getLeaderboardSeries({
  externalId,
  interval: "hour",
  from: "2026-09-01T00:00:00Z",
  to: "2026-09-02T00:00:00Z",
});
// series.points: 24 hours, each with start, realizedPnl, cumulativeRealizedPnl, ...

Realized P&L is booked when a sell is placed or a position settles, so an hour in which a user only held positions shows 0, however prices moved.

On this page