---
title: "Get ranked leaderboard standings for a campaign"
method: GET
path: "/campaigns/{campaign_id}/leaderboard"
tags: ["Campaigns"]
---

# Get ranked leaderboard standings for a campaign

`GET /campaigns/{campaign_id}/leaderboard`

## Request

- Base URL: `https://api.reacherapp.com/public/v1`
- URL: `https://api.reacherapp.com/public/v1/campaigns/{campaign_id}/leaderboard`
- Auth: API key in header `x-api-key` and API key in header `x-shop-id`

Ranked creator standings for a Leaderboard (contest) campaign: each creator's `rank`, weighted `composite_score` with a per-metric `score_breakdown`, and the raw GMV / views / videos / units stats. When the campaign has a currently-live (or recently-ended) micro-challenge, its windowed blitz board is nested under `micro_challenge`. Standings are paginated; `total_creators` is the full participant count. Scores come from the same shared scorer the dashboard and public share page use, so ranks agree across every surface. Single-shop only (the shop sets the response currency).

## Path parameters

- `campaign_id` integer, required

## Query parameters

- `page` integer: Page number (1-indexed).
- `page_size` integer: Standings per page (max 100).

## Response `200`

Successful Response

- CampaignLeaderboardResponse: 200 response for ``GET /campaigns/{campaign_id}/leaderboard``. Ranked standings for a leaderboard (contest) campaign plus, when one is active/recently-ended, the nested micro-challenge board. ``standings`` is paginated; ``total_creators`` is the full participant count. Scores are computed by the same shared scorer the brand dashboard and public share page use, so ranks agree across every surface.
  - `campaign_id` integer, required
  - `campaign_name` string
  - `scoring_mode` 'single' | 'weighted': `single` | `weighted`.
  - `metric_type` union: Ranking metric for single-metric campaigns; the composite's tie-break/display metric for weighted.
    - 'gmv' | 'views' | 'videos_posted' | 'units_sold' | 'avg_views_per_post' | 'gmv_and_live_gmv' | 'videos_gmv_and_live_gmv'
    - string
  - `weighted_metrics` object[], nullable: Metric/weight pairs (summing to 100) for weighted campaigns; null for single-metric.
  - `start_date` string, nullable
  - `end_date` string, nullable
  - `currency` string
  - `currency_code` string: Deprecated alias of `currency`; use `currency`.
  - `currency_symbol` string
  - `standings` LeaderboardStanding[]
    - `rank` integer, nullable: Compacted prize rank, 1-indexed. Null when the creator is disqualified by the campaign's minimum-activity requirement (unranked). Disqualified creators don't consume a prize place; tied creators share one (the following rank skips accordingly, e.g. 1, 1, 3), so each rank agrees with the prize it pays.
    - `creator_id` string, nullable: Reacher creator-account id. Null only for a legacy mapping row with no linked account.
    - `handle` string, required: Display handle: TikTok username, else full name, else `Creator`.
    - `creator_name` string, nullable: Creator's full name. Null when no name is on file.
    - `avatar_url` string, nullable
    - `composite_score` number, nullable: 0-100 weighted composite. Null for single-metric campaigns (rank comes straight from `metric_type`).
    - `score_breakdown` ScoreBreakdownItem[], nullable: Per-metric contribution breakdown. Null for single-metric campaigns.
      - `metric_type` union, required: `gmv` | `views` | `videos_posted` | `units_sold` | `avg_views_per_post`.
        - 'gmv' | 'views' | 'videos_posted' | 'units_sold' | 'avg_views_per_post' | 'gmv_and_live_gmv' | 'videos_gmv_and_live_gmv'
        - string
      - `weight` integer, required: This metric's weight (0-100). Weights across the campaign sum to 100.
      - `contribution` number, required: Weighted points this metric added to the composite (0-`weight`). Zero for everyone until a leader emerges on the metric.
      - `raw_value` number, required: The creator's raw metric value before normalization (e.g. GMV in the shop currency, view count).
    - `gmv` number, required: Video-attributed GMV in the shop currency. Meaning is unchanged by LIVE metrics — see `live_gmv`/`combined_gmv`.
    - `views` integer
    - `videos_posted` integer
    - `units_sold` integer
    - `avg_views_per_post` number: `views / videos_posted`, 0 when no videos.
    - `live_gmv` number: LIVE GMV attributed to this creator, restricted to the campaign's products. 0 for campaigns with no LIVE metric.
    - `live_session_count` integer: In-window LIVE sessions that sold a campaign product.
    - `combined_gmv` number: `gmv + live_gmv`. The ranking value for the `gmv_and_live_gmv` and `videos_gmv_and_live_gmv` metrics.
    - `frozen` boolean: True when this standing is pinned by the campaign's locked board and can no longer change. False on a live board, and for a creator added after the lock (live values, listed after the locked standings).
  - `micro_challenge` MicroChallengeBoardResponse: The nested micro-challenge ("blitz") board for a parent campaign. A micro-challenge is a windowed sub-contest. Its standings are scored over videos posted inside ``[window_start_at, window_end_at)`` only. Populated when a window is currently live, or was live within the last 7 days; otherwise the parent response's ``micro_challenge`` is null.
    - `micro_campaign_id` integer, required
    - `name` string
    - `window_start_at` string, nullable
    - `window_end_at` string, nullable
    - `status` 'live' | 'ended': `live` | `ended`.
    - `scoring_mode` 'single' | 'weighted': `single` | `weighted`.
    - `metric_type` union
      - 'gmv' | 'views' | 'videos_posted' | 'units_sold' | 'avg_views_per_post' | 'gmv_and_live_gmv' | 'videos_gmv_and_live_gmv'
      - string
    - `standings` LeaderboardStanding[]
      - `rank` integer, nullable: Compacted prize rank, 1-indexed. Null when the creator is disqualified by the campaign's minimum-activity requirement (unranked). Disqualified creators don't consume a prize place; tied creators share one (the following rank skips accordingly, e.g. 1, 1, 3), so each rank agrees with the prize it pays.
      - `creator_id` string, nullable: Reacher creator-account id. Null only for a legacy mapping row with no linked account.
      - `handle` string, required: Display handle: TikTok username, else full name, else `Creator`.
      - `creator_name` string, nullable: Creator's full name. Null when no name is on file.
      - `avatar_url` string, nullable
      - `composite_score` number, nullable: 0-100 weighted composite. Null for single-metric campaigns (rank comes straight from `metric_type`).
      - `score_breakdown` ScoreBreakdownItem[], nullable: Per-metric contribution breakdown. Null for single-metric campaigns.
        - `metric_type` union, required: `gmv` | `views` | `videos_posted` | `units_sold` | `avg_views_per_post`.
          - 'gmv' | 'views' | 'videos_posted' | 'units_sold' | 'avg_views_per_post' | 'gmv_and_live_gmv' | 'videos_gmv_and_live_gmv'
          - string
        - `weight` integer, required: This metric's weight (0-100). Weights across the campaign sum to 100.
        - `contribution` number, required: Weighted points this metric added to the composite (0-`weight`). Zero for everyone until a leader emerges on the metric.
        - `raw_value` number, required: The creator's raw metric value before normalization (e.g. GMV in the shop currency, view count).
      - `gmv` number, required: Video-attributed GMV in the shop currency. Meaning is unchanged by LIVE metrics — see `live_gmv`/`combined_gmv`.
      - `views` integer
      - `videos_posted` integer
      - `units_sold` integer
      - `avg_views_per_post` number: `views / videos_posted`, 0 when no videos.
      - `live_gmv` number: LIVE GMV attributed to this creator, restricted to the campaign's products. 0 for campaigns with no LIVE metric.
      - `live_session_count` integer: In-window LIVE sessions that sold a campaign product.
      - `combined_gmv` number: `gmv + live_gmv`. The ranking value for the `gmv_and_live_gmv` and `videos_gmv_and_live_gmv` metrics.
      - `frozen` boolean: True when this standing is pinned by the campaign's locked board and can no longer change. False on a live board, and for a creator added after the lock (live values, listed after the locked standings).
  - `total_creators` integer, required: Full participant count (active + Paid/Settled), independent of pagination.
  - `standings_frozen` boolean: True once the board is locked. Standings then stop changing: every metric and rank comes from the locked snapshot.
  - `standings_frozen_at` string, nullable: ISO-8601 timestamp the board locked. Null while live.
  - `standings_frozen_reason` string, nullable: What locked it: `end_lag` (2 days after the close, the affiliate-sync lag), `first_payout`, `stop_close` (a stop condition tripped), `exclusion` (re-locked after a video exclusion), `manual_backfill`, or `legacy`. Null while live.
  - `standings_period_end` string, nullable: Last day (YYYY-MM-DD, shop-local) the board counts sales for: the earlier of `end_date` and a stop-condition trip. Sales after it never reach the standings. Null for an open-ended campaign that is still running.
  - `values_windowed` boolean: True when `gmv`, `views`, `units_sold` and `videos_posted` are bounded to the campaign period (the normal case). False only while the daily ledger is unreachable: the board then shows lifetime values, which equal the windowed ones for a running campaign and overstate a campaign closed within the last two days. A locked board is never served unwindowed.
  - `as_of` string, required: ISO-8601 UTC timestamp the standings were computed. On a locked board the values have not changed since `standings_frozen_at`.
  - `pagination` CommunitySchemasCommonPaginationMeta, required: Pagination metadata returned in list responses.
    - `page` integer, required
    - `page_size` integer, required
    - `total_count` integer, required
    - `total_pages` integer, required

## Other responses

- `422`: Validation Error

## Changes

> 76 revisions in range; 1 not diffed.

- **2026-09-19** `291230805105`: 4 breaking, 6 warning, 7 info
  - the `metric_type` response's property type changed from `string` to no type for status `200`
  - the `micro_challenge/anyOf[subschema #1: MicroChallengeBoardResponse]/metric_type` response's property type changed from `string` to no type for status `200`
  - the `micro_challenge/anyOf[subschema #1: MicroChallengeBoardResponse]/standings/items/score_breakdown/anyOf[subschema #1]/items/metric_type` response's property type changed from `string` to no type for status `200`
  - the `standings/items/score_breakdown/anyOf[subschema #1]/items/metric_type` response's property type changed from `string` to no type for status `200`
  - …13 more
- **2026-09-05** `643422c93bd8`: 7 info
  - added the optional property `micro_challenge/anyOf[subschema #1: MicroChallengeBoardResponse]/standings/items/frozen` to the response with the `200` status
  - added the optional property `standings/items/frozen` to the response with the `200` status
  - added the optional property `standings_frozen` to the response with the `200` status
  - added the optional property `standings_frozen_at` to the response with the `200` status
  - …3 more

[Operation history](https://skmtc.dev/reacherapp/apis/reacher-data-api/changes/campaigns/:campaign_id/leaderboard/get.md)

---

[API](https://skmtc.dev/reacherapp/apis/reacher-data-api.md) - [All operations](https://skmtc.dev/reacherapp/apis/reacher-data-api/llms.txt) - [OpenAPI document](https://skmtc.dev/reacherapp/apis/reacher-data-api/revisions/63ce74b30b5a?raw)
