Overview
Identify boards with their dashboard key (e.g. "weekly_high_score"). Every method has a parallel …ById overload if you prefer the leaderboard's UUID.
Rotation & instances
Each leaderboard has a rotation schedule (manual, daily, weekly, monthly…). Every rotation cycle is stored as its own instance: when a board rotates the previous instance is marked closed (its scores are preserved forever) and a new open instance starts collecting submissions.
Players are sticky to the instance they first submitted to in a given cycle, so within a rotation a player always competes against the same field. The dashboard "Capacity" setting (e.g. top 100) is enforced per instance - older low-ranked scores are evicted as new players push in.
instanceId to GetScores / GetScoresAroundPlayer to read a specific past cycle. Without it you get the current open instance.Dashboard
Open a leaderboard from Project → Leaderboards to get a dedicated page with three tabs:
- Live - the current open instance, with paginated / top-N / range view modes and inline edit + delete on each score.
- History - pick any closed instance from the dropdown to inspect its final standings (this is what your players see when they query
GetLastClosedResult). - Stats - total scores, unique players, all-time best, and a per-instance volume chart so you can see how submissions trend across rotation cycles.
Listing boards
1var boards = await Leaderboards.List();2foreach (var b in boards) Debug.Log($"{b.key}: {b.name}");Submitting a score
1var result = await Leaderboards.Submit(2 leaderboardKey: "weekly_high_score",3 score: 12_500,4 playerName: "Cipher",5 metadata: new System.Collections.Generic.Dictionary<string, string> {6 { "character", "ranger" }7 }8);9if (result.success) Debug.Log($"Rank {result.rank}");playerId defaults to KalmForgeIdentity.PlayerId. Pass an explicit value only if you're submitting on behalf of another player from server code.Reading scores
1var top10 = await Leaderboards.GetScores("weekly_high_score", limit: 10);2var page2 = await Leaderboards.GetScores("weekly_high_score", limit: 10, offset: 10);34// Read a specific past instance:5var historic = await Leaderboards.GetScores("weekly_high_score", instanceId: "...");Around the player
1var slice = await Leaderboards.GetScoresAroundPlayer(2 "weekly_high_score", before: 5, after: 53);4// Returns 11 entries centred on the calling player (or empty if no score yet).56var mine = await Leaderboards.GetMyScore("weekly_high_score");Rotation details
1var d = await Leaderboards.GetDetails("weekly_high_score");2Debug.Log($"resets in {d.time_remaining_seconds}s, {d.current_player_count} players");Player statistics
1var stats = await Leaderboards.GetPlayerStatistics("weekly_high_score");2Debug.Log($"best #{stats.best_rank} (avg {stats.average_score:F1}) over {stats.total_rotations} weeks");Last week's result & rewards
For "you placed Nth last week, here's your reward" flows, query the most recent closed instance the player participated in. The result includes their final rank, score, and whether they've already claimed a reward for it.
1// On app launch / main menu:2var last = await Leaderboards.GetLastClosedResult("weekly_high_score");3if (last.found && !last.claimed) {4 // Show the "you placed #X with Y points last week!" UI56 var claim = await Leaderboards.ClaimLastClosedReward("weekly_high_score");7 if (claim.newly_claimed) {8 GrantInGameReward(claim.rank, claim.score);9 }10}GetLastClosedResult is a read; ClaimLastClosedRewardatomically marks the reward as claimed. A player can only successfully claim each closed instance once - repeat calls returnalready_claimed = true.Renaming the player
1bool ok = await Leaderboards.UpdatePlayerName("NewName");Renames the player across every board and instance in the project. Call this once when the player picks or changes their display name.
API reference
| Name | Type | Description |
|---|---|---|
| List() | Task<List<LeaderboardInfo>> | All boards configured for the project. |
| Submit(key, score, playerId?, playerName?, metadata?) | Task<SubmitResult> | Submit by stable key. |
| SubmitById(id, …) | Task<SubmitResult> | Submit by leaderboard UUID. |
| GetScores(key, limit=50, offset=0, instanceId?) | Task<List<LeaderboardEntry>> | Top entries for the current or a specific instance. |
| GetScoresById(id, …) | Task<List<LeaderboardEntry>> | Same, by id. |
| GetScoresAroundPlayer(key, before=5, after=5, playerId?, instanceId?) | Task<List<LeaderboardEntry>> | Window centred on the player. |
| GetMyScore(key) | Task<LeaderboardEntry> | Convenience: just the calling player's entry. |
| GetDetails(key, playerId?) | Task<LeaderboardDetails> | Rotation timing + counts. Pass playerId to scope to their sticky instance. |
| GetPlayerStatistics(key, playerId?) | Task<PlayerStatistics> | Best/worst/average across all past instances. |
| GetLastClosedResult(key, playerId?) | Task<LastClosedResult> | Final rank+score from the most recent closed instance the player was in. |
| ClaimLastClosedReward(key, playerId?) | Task<LastClosedResult> | Atomically claim the previous-instance reward exactly once. |
| UpdatePlayerName(newName, playerId?) | Task<bool> | Rename across every board & instance in the project. |
REST endpoint
1POST /api/public/sdk/leaderboards2Headers: X-API-Key: kf_xxx_yyy34# All actions go through one endpoint with an "action" field:5{ "action": "submit", "leaderboard_key": "weekly_high_score",6 "player_id": "...", "player_name": "Cipher", "score": 12500,7 "metadata": { "character": "ranger" } }89{ "action": "scores", "leaderboard_key": "...", "limit": 50, "offset": 0 }10{ "action": "around_player", "leaderboard_key": "...", "player_id": "...", "before": 5, "after": 5 }11{ "action": "details", "leaderboard_key": "...", "player_id": "..." }12{ "action": "player_statistics", "leaderboard_key": "...", "player_id": "..." }13{ "action": "update_player_name", "player_id": "...", "player_name": "..." }14{ "action": "last_closed_result", "leaderboard_key": "...", "player_id": "..." }15{ "action": "claim_last_closed_reward", "leaderboard_key": "...", "player_id": "..." }1617# GET to list:18GET /api/public/sdk/leaderboards