> ## Documentation Index
> Fetch the complete documentation index at: https://developers.teambuilder.ge/llms.txt
> Use this file to discover all available pages before exploring further.

# Leaderboards

> Rank employees by XP for a period, company-wide or within a department, and show every department's leaders at once.

TeamBuilder ranks **individuals by XP**. Two endpoints expose the ranking, both with the `leaderboard:read` scope:

| Endpoint | Use it for |
| - | - |
| [`GET /v1/leaderboard`](/api-reference/leaderboard/get-the-leaderboard) | A ranked list, company-wide or filtered to one department, paginated. |
| [`GET /v1/leaderboard/by-department`](/api-reference/leaderboard/get-the-leaderboard-by-department) | Every department's top members in one response, for overview screens. |

## Periods

Pass `period` to choose the XP window. Windows are calendar months in UTC and always include the current month.

| `period` | Ranks by | Example on 20 October 2026 |
| - | - | - |
| `all_time` (default) | Total XP ever earned | Everything |
| `this_month` | XP earned since the 1st of this month | From 1 October 2026 |
| `last_3_months` | XP earned since the 1st of the month two months ago | From 1 August 2026 |
| `last_year` | XP earned since the 1st of the month eleven months ago | From 1 November 2025 |

```bash theme={null}
curl "https://api.teambuilder.ge/v1/leaderboard?period=last_3_months&limit=25" \
  -H "Authorization: Bearer $TEAMBUILDER_API_KEY"
```

In every row, `xp` is the XP earned in the period, and it is what decides the order. `level` is always derived from all-time XP, whatever the period, so a long-standing employee keeps a high level on a quiet month.

<Note>
  Every active employee appears, including people with no XP in the period. Windowed XP is a net figure: an admin's manual correction can make it zero or, rarely, negative.
</Note>

## What `rank` means

* `rank` is the employee's **company-wide position** for the period, starting at 1.
* Ranks are unique. Employees with equal XP get consecutive ranks in a stable order, so ties never share a number and never reshuffle between requests.
* Under a department filter, each row **keeps its company-wide rank**. The filtered list can therefore read 2, 7, 15. To show a position within the department, number the rows yourself as you walk the pages.

## Filtering to a department

Pass a `department_id` from [`GET /v1/departments`](/api-reference/departments/list-departments) (or from any employee's `department.id`):

```bash theme={null}
curl "https://api.teambuilder.ge/v1/leaderboard?period=this_month&department_id=b7e0c4d2-1f3a-4e8b-9c6d-2a5f8e1b7c90" \
  -H "Authorization: Bearer $TEAMBUILDER_API_KEY"
```

The filter matches the department's **direct members** only; members of its sub-departments are not included. An id that is not one of your departments returns `404 not_found`.

## Grouped by department

[`GET /v1/leaderboard/by-department`](/api-reference/leaderboard/get-the-leaderboard-by-department) returns every active department with its top members for the period, in a single page. An archived department that still has members is listed too, so nobody drops out of the view:

```bash theme={null}
curl "https://api.teambuilder.ge/v1/leaderboard/by-department?period=this_month&limit_per_department=1" \
  -H "Authorization: Bearer $TEAMBUILDER_API_KEY"
```

```json Response theme={null}
{
  "data": [
    {
      "department": {
        "id": "b7e0c4d2-1f3a-4e8b-9c6d-2a5f8e1b7c90",
        "external_id": "D-ENG",
        "name": "Engineering"
      },
      "department_total_xp": 5150,
      "member_count": 14,
      "leaders": [
        {
          "rank": 1,
          "employee_id": "3f1c2a9e-8d4b-4c61-9a57-0e2b6f7d1a43",
          "external_id": "EMP-00042",
          "name": "Nino Beridze",
          "department": {
            "id": "b7e0c4d2-1f3a-4e8b-9c6d-2a5f8e1b7c90",
            "external_id": "D-ENG",
            "name": "Engineering"
          },
          "level": 12,
          "xp": 2300
        }
      ]
    },
    {
      "department": null,
      "department_total_xp": 1250,
      "member_count": 3,
      "leaders": [
        {
          "rank": 3,
          "employee_id": "5d2b8e6f-1a7c-4e39-a0d4-8c6f2b9e1a57",
          "external_id": "EMP-00213",
          "name": "Mariam Lomidze",
          "department": null,
          "level": 9,
          "xp": 950
        }
      ]
    }
  ],
  "pagination": { "next_cursor": null }
}
```

* Groups are ordered by department name, case-insensitively. Active departments without members are listed too, with `member_count: 0` and no leaders. The group of employees without a department has `department: null`, is always last, and appears only when it has members.
* `leaders` holds the top `limit_per_department` members (1–25, default 5), or every member when the group is smaller, each with their company-wide rank.
* `department_total_xp` and `member_count` are informational. **Departments are not ranked against each other**: comparing a team of 4 with a team of 40 by total or average XP rewards size, not engagement, so TeamBuilder deliberately offers no department-versus-department ranking.

## No coins on leaderboards

Leaderboards never include coin balances, by design. Coins are a spendable currency: ranking by balance would push down anyone who redeems a reward, and a public list of balances shows what colleagues have spent. XP is never spent, so it is a fair, private-enough basis for a ranking.

To show someone their own balance, read it from [employee stats](/guides/employee-widgets).

## Refresh cadence

Rankings are computed by TeamBuilder and cached for up to **30 seconds**, so a response can be that old.

<Tip>
  Fetch each view you display (period × department) on your server at most **once a minute**, cache the result, and serve every page view from your cache. For office screens and dashboards, a refresh every one to five minutes looks live and stays far inside the [rate limit](/reference/rate-limits).
</Tip>

## Paging through a full board

`GET /v1/leaderboard` is cursor-paginated (`limit` 1–100, default 25). While employees earn XP, rows can move between pages, so a page-by-page walk of a large board is approximate: a row may repeat or be skipped. Display the first page or two, and if you need a complete export, de-duplicate by `employee_id`. See [Pagination](/reference/pagination).

## Names

`name` is the employee's account name once they have signed in to TeamBuilder. Before that it is the name your [roster sync](/guides/roster-sync) sent, or `null` when there is none. Always render a fallback, such as "New teammate".


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.