Leaderboards API
Read leaderboard rankings by code and time window, fetch a single participant’s rank, score, and percentile, and manage leaderboard definitions through admin endpoints. Participant endpoints are read-only; rankings are computed from the underlying points and scoring data.
AuthAll endpoints require an X-API-Key header. Production keys are prefixed bq_live_; sandbox keys bq_test_.
ScopesParticipant key Read leaderboard rankings and participant rank with any valid API key.
Admin scope Manage leaderboard definitions: requires admin or gamify:admin scope.
Base URLhttps://YOUR_API_DOMAIN/api/v1/gamify
Endpoint inventory
| Method | Endpoint | Purpose |
|---|
| GET | /gamify/leaderboards/{code} | Top rankings for a leaderboard. Optional time-period filter. |
| GET | /gamify/leaderboards/{code}/rank/{participant_id} | Individual rank, score, and percentile. |
| GET | /gamify/admin/leaderboards | List leaderboard definitions. Admin scope. |
| POST | /gamify/admin/leaderboards | Create a leaderboard definition. Admin scope. |
| GET | /gamify/admin/leaderboards/{leaderboard_id} | Get one leaderboard definition. Admin scope. |
| PATCH | /gamify/admin/leaderboards/{leaderboard_id} | Update a leaderboard definition. Admin scope. |
| DELETE | /gamify/admin/leaderboards/{leaderboard_id} | Deactivate (soft-delete) a leaderboard. Admin scope. |
GET/api/v1/gamify/leaderboards/{code}
Participant key
Returns the top ranked participants for a leaderboard. Supply an optional time-window filter; when omitted, the leaderboard definition's default window is used.
Path parameters
| Field | Type | Description |
|---|
| coderequired | str | Code of the leaderboard to read (matches the code on the active leaderboard definition). |
Query parameters
| Field | Type | Description |
|---|
| limit | int | Number of entries to return. 1 to 100. Default: 20 |
| period | Optional[str] | Time window override. One of: all_time, yearly, monthly, weekly, daily. Defaults to the leaderboard definition's configured time_window. |
GET /api/v1/gamify/leaderboards/top_scorers?limit=10&period=monthly
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| leaderboard_code | str | Echo of the requested leaderboard code. |
| period | str | Effective time window for this response (one of all_time, yearly, monthly, weekly, daily). |
| period_key | str | Concrete period key the response covers (for example, 2026-05 for a monthly window). Useful for caching and labelling. |
| entries | list[LeaderboardEntryResponse] | Ranked entries. Each entry: { rank: int, participant_id: str, display_name?: str, score: int, change?: str (one of up, down, same, new) }. |
| total_participants | int | Total participants tracked in this period. Default: 0 |
{
"leaderboard_code": "top_scorers",
"period": "monthly",
"period_key": "2026-05",
"entries": [
{ "rank": 1, "participant_id": "user_456", "display_name": "Maya", "score": 5000, "change": "up" },
{ "rank": 2, "participant_id": "user_123", "display_name": "Arjun", "score": 4500, "change": "same" },
{ "rank": 3, "participant_id": "user_789", "score": 4200, "change": "new" }
],
"total_participants": 1250
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
| 404 | leaderboard_not_found | No active leaderboard definition exists for the supplied code. |
GET/api/v1/gamify/leaderboards/{code}/rank/{participant_id}
Participant key
Returns the rank, score, and percentile of a single participant within the leaderboard. Useful when you only need to surface 'you are #42 of 1,250' without loading the full ranking.
Path parameters
| Field | Type | Description |
|---|
| coderequired | str | Code of the leaderboard to query. |
| participant_idrequired | str | Your participant identifier. |
GET /api/v1/gamify/leaderboards/top_scorers/rank/user_123
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the requested participant id. |
| rank | Optional[int] | 1-indexed rank within the leaderboard. null when the participant has no qualifying score for this window. |
| score | int | Participant's current score in this period. Default: 0 |
| total_participants | int | Total participants tracked in this period. Default: 0 |
| percentile | Optional[float] | Percentile placement (higher is better). null when the participant is unranked or the leaderboard has no entries. |
{
"participant_id": "user_123",
"rank": 2,
"score": 4500,
"total_participants": 1250,
"percentile": 99.8
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
| 404 | leaderboard_not_found | No active leaderboard definition exists for the supplied code. |
GET/api/v1/gamify/admin/leaderboards
Admin scope
List leaderboard definitions for the tenant. Returns a paginated set ordered by display_order.
Query parameters
| Field | Type | Description |
|---|
| is_active | Optional[bool] | When set, filters to definitions where is_active matches. |
| page | int | 1-indexed page number. Default: 1 |
| page_size | int | Items per page. Max 100. Default: 50 |
GET /api/v1/gamify/admin/leaderboards?is_active=true&page=1&page_size=50
X-API-Key: bq_live_xxxxx # must carry admin or gamify:admin scope
LeaderboardResponse item fields
| Field | Type | Description |
|---|
| id | UUID | Unique identifier for the leaderboard definition. |
| tenant_id | UUID | Owning tenant. |
| code | str | Unique code per tenant. Used by participant endpoints. |
| name | str | Display name. |
| description | Optional[str] | Optional long-form description. |
| metric | str | Metric the leaderboard ranks on (points, badge_count, streak_current, and similar). |
| metric_config | Optional[dict] | Free-form configuration for the chosen metric. |
| time_window | str | Default time window: all_time, yearly, monthly, weekly, or daily. |
| scope | str | global or engagement (engagement-scoped boards only count facts from one engagement). |
| engagement_id | Optional[UUID] | Engagement filter when scope is engagement. |
| max_entries | int | Hard cap on entries computed per period (1 to 1000). |
| show_participant_rank | bool | Whether SDKs should surface the current participant's own rank alongside the list. |
| anonymize_names | bool | When true, SDKs/clients should mask display_name on rendered rows. |
| min_score | int | Minimum score required to appear on the board. |
| reset_cron | Optional[str] | Cron expression for automated rollovers (informational; runtime handles the rollover). |
| cache_ttl_seconds | int | How long computed rankings may be cached. |
| last_calculated_at | Optional[datetime] | Timestamp of the last full re-computation. |
| icon_url | Optional[str] | Optional icon URL. |
| color | Optional[str] | Optional hex color (max 20 chars). |
| is_active | bool | Soft-delete flag; false hides the board from participant endpoints. |
| is_public | bool | Whether the board is exposed to participant endpoints at all. |
| display_order | int | Sort key when listing boards in dashboards/SDKs. |
| created_at | datetime | Creation timestamp. |
| updated_at | datetime | Last update timestamp. |
{
"items": [
{
"id": "01HZ...",
"tenant_id": "01HZ...",
"code": "top_scorers",
"name": "Top Scorers",
"description": "Lifetime points leaders.",
"metric": "points",
"metric_config": null,
"time_window": "monthly",
"scope": "global",
"engagement_id": null,
"max_entries": 100,
"show_participant_rank": true,
"anonymize_names": false,
"min_score": 0,
"reset_cron": "0 0 1 * *",
"cache_ttl_seconds": 60,
"last_calculated_at": "2026-05-24T07:00:00Z",
"icon_url": null,
"color": "#1F3A60",
"is_active": true,
"is_public": true,
"display_order": 0,
"created_at": "2026-01-10T08:00:00Z",
"updated_at": "2026-05-01T00:00:00Z"
}
],
"total": 4,
"page": 1,
"page_size": 50
}
POST/api/v1/gamify/admin/leaderboards
Admin scope
Create a leaderboard definition. Returns the new definition with a 201 status.
Request body
| Field | Type | Description |
|---|
| coderequired | str | Unique code per tenant. 1 to 50 chars. Used by participant endpoints; cannot be changed after creation. |
| namerequired | str | Display name. 1 to 100 chars. |
| description | Optional[str] | Optional long-form description. |
| metric | str | Metric to rank on (points, badge_count, streak_current, and similar). Default: "points" |
| metric_config | Optional[dict] | Free-form configuration for the chosen metric. |
| time_window | str | Default time window: all_time, yearly, monthly, weekly, or daily. Default: "all_time" |
| scope | str | global or engagement. Default: "global" |
| engagement_id | Optional[UUID] | Engagement filter; required when scope is engagement. |
| max_entries | int | Hard cap on entries (1 to 1000). Default: 100 |
| show_participant_rank | bool | Whether SDKs surface the participant's own rank alongside the list. Default: true |
| anonymize_names | bool | When true, clients should mask display_name on rendered rows. Default: false |
| min_score | int | Minimum score required to appear (>= 0). Default: 0 |
| reset_cron | Optional[str] | Cron expression for automated rollovers. |
| icon_url | Optional[str] | Optional icon URL. |
| color | Optional[str] | Optional hex color. Max 20 chars. |
| is_public | bool | Expose to participant endpoints. Default: true |
| display_order | int | Sort key when listing boards. Default: 0 |
POST /api/v1/gamify/admin/leaderboards
X-API-Key: bq_live_xxxxx # admin or gamify:admin scope
Content-Type: application/json
{
"code": "top_scorers",
"name": "Top Scorers",
"description": "Lifetime points leaders.",
"metric": "points",
"time_window": "monthly",
"scope": "global",
"max_entries": 100,
"reset_cron": "0 0 1 * *",
"color": "#1F3A60"
}
Errors
| Status | Code | When it fires |
|---|
| 400 | leaderboard_code_conflict | Another leaderboard definition already uses that code for this tenant. |
| 403 | forbidden | API key is missing the admin or gamify:admin scope. |
GET/api/v1/gamify/admin/leaderboards/{leaderboard_id}
Admin scope
Retrieve one leaderboard definition by its UUID. Response shape matches the items in the list endpoint.
Errors
| Status | Code | When it fires |
|---|
| 404 | leaderboard_not_found | No leaderboard exists for the supplied leaderboard_id. |
PATCH/api/v1/gamify/admin/leaderboards/{leaderboard_id}
Admin scope
Partial update of a leaderboard definition. All body fields are optional; only supplied fields are changed. code cannot be changed.
Request body (all optional)
| Field | Type | Description |
|---|
| name | Optional[str] | 1 to 100 chars. |
| description | Optional[str] | Long-form description. |
| metric | Optional[str] | Switches the metric the board ranks on. |
| metric_config | Optional[dict] | Replaces metric configuration entirely. |
| time_window | Optional[str] | all_time, yearly, monthly, weekly, or daily. |
| scope | Optional[str] | global or engagement. |
| engagement_id | Optional[UUID] | Engagement filter when scope is engagement. |
| max_entries | Optional[int] | 1 to 1000. |
| show_participant_rank | Optional[bool] | |
| anonymize_names | Optional[bool] | |
| min_score | Optional[int] | >= 0. |
| reset_cron | Optional[str] | Cron expression for automated rollovers. |
| icon_url | Optional[str] | |
| color | Optional[str] | Hex color, max 20 chars. |
| is_active | Optional[bool] | Set false to hide from participant endpoints without losing history. |
| is_public | Optional[bool] | |
| display_order | Optional[int] | Sort key when listing boards. |
Errors
| Status | Code | When it fires |
|---|
| 404 | leaderboard_not_found | No leaderboard exists for the supplied leaderboard_id. |
DELETE/api/v1/gamify/admin/leaderboards/{leaderboard_id}
Admin scope
Soft-delete the leaderboard by setting is_active to false. Existing entries are preserved; participant endpoints stop serving the board.
{ "message": "Leaderboard deactivated" }
Errors
| Status | Code | When it fires |
|---|
| 404 | leaderboard_not_found | No leaderboard exists for the supplied leaderboard_id. |