LEADERBOARDS
Every high score deserves a place
Rank scores, times, counts or completion rates. The platform manages player identity, personal bests and standings; your game reports round starts and final results.
Three steps
- Create a board
Game page → Leaderboard settings: higher or lower is better, the unit, the score range and the minimum play time. Up to 10 boards per game.
- Connect start and finish
No SDK needed. Get a runId when a round starts and submit the real integer score at the end.
- Test on the site
Check personal bests, ties, retries and a new round. If the leaderboard is down, the game still plays.
APIs and examples
| When | Endpoint | Key detail |
|---|---|---|
| Read settings | GET /api/v1/games/{gameId}/leaderboards | Enabled boards |
| Round start | POST /api/v1/leaderboards/{boardId}/runs | Player token + new request key |
| Final result | POST /api/v1/runs/{runId}/score | {"score":12800} |
| Standings | GET /api/v1/leaderboards/{boardId}/entries | limit and cursor pagination |
| My rank | GET /api/v1/leaderboards/{boardId}/me?around=2 | Personal result and neighbors |
Native JavaScript / REST example
Replace the platform origin and YOUR_BOARD_ID with the generated configuration, then connect the calls to actual round-start and game-over events.
const platform = 'https://www.ai-made.games';
const boardId = 'YOUR_BOARD_ID';
function getPlayerSession() {
return new Promise((resolve, reject) => {
const requestId = crypto.randomUUID();
const finish = (error, session) => {
clearTimeout(timer);
window.removeEventListener('message', receive);
error ? reject(error) : resolve(session);
};
const receive = (event) => {
const data = event.data;
if (event.source !== window.parent || event.origin !== platform ||
!data || data.source !== 'aimadegames-platform' ||
data.type !== 'leaderboard-session' || data.requestId !== requestId) return;
if (data.error) return finish(new Error(data.error));
if (data.apiOrigin !== platform || !data.session?.token) return;
finish(null, data.session);
};
const timer = setTimeout(() => finish(new Error('Session timeout')), 15000);
window.addEventListener('message', receive);
window.parent.postMessage({source:'aimadegames', type:'leaderboard-session', requestId}, platform);
});
}
async function request(path, token, body, key) {
const response = await fetch(platform + '/api/v1/' + path, {
method: key ? 'POST' : 'GET', credentials: 'omit',
headers: {Authorization: 'Bearer ' + token,
...(key ? {'Idempotency-Key': key} : {}),
...(body ? {'Content-Type': 'application/json'} : {})},
body: body ? JSON.stringify(body) : undefined,
signal: AbortSignal.timeout(15000)
});
const data = await response.json();
if (!response.ok) throw Object.assign(new Error(data.error?.message), {
code: data.error?.code, retryAfter: response.headers.get('Retry-After')
});
return data;
}
// Save these per round. Reuse the same keys when retrying that round.
const startKey = crypto.randomUUID();
const scoreKey = crypto.randomUUID();
const session = await getPlayerSession();
const run = await request('leaderboards/' + boardId + '/runs', session.token, null, startKey);
// At final game-over, use the actual integer score from your game:
async function submitFinalScore(score) {
// Refreshing the token preserves this player's run.
const current = Date.parse(session.expiresAt) <= Date.now() + 60000
? await getPlayerSession() : session;
return request('runs/' + run.runId + '/score', current.token, {score}, scoreKey);
}
// Catch failures in your game's event handlers so gameplay can continue.
// Retry settlement with the SAME run, scoreKey and final score.
// For a new round create new keys and call the start endpoint again.Tokens, scoring and retries
- Get a one-hour player token through the parent’s leaderboard-session handshake. Validate the parent window, exact origin, request ID and returned apiOrigin. Keep tokens in memory; use credentials: omit.
- Use separate UUID Idempotency-Key values for start and settlement. Retries keep the original key, runId and score; new rounds use new keys. A run can be settled within two hours.
- Time boards use integer milliseconds; submit 9820 for 98.2%. Scoring rules are immutable; create a new board when gameplay requires incompatible rules.
- Guest and account scores are separate. Client-reported scores are for casual play and are not anti-cheat verified.
Before launch
Try each one from Start game on the game page. Ticks are notes for you and stay in this browser.
Leaderboards
0 of 6Get materials for my game →Full API reference ↗
Stuck? Send us the error and your prompt here.