Developer guide
ScorePerch gives your game online leaderboards with two HTTP calls. There are no player accounts: your game creates a random player_id (a UUID) once, stores it, and sends it with a nickname.
1. Get set up
- Create a free developer account and verify your email.
- Create a game. You get a Game Key (
gk_…, public, safe to ship) and a signing secret (gs_…, used to sign score posts). - Add boards — one per level or mode. "Add numbered boards" creates
level-1…level-Nin one go. Each board says whether lower is better (times) or higher is better (points), and can reject impossible values. - Optionally turn on the game's public page (
/games/{slug}: leaderboards + support) and its generated privacy page (/games/{slug}/privacy), handy as App Store / Google Play URLs.
Accounts can have up to 3 games with up to 200 boards each. ScorePerch is free.
2. Post a result
POST https://scoreperch.com/api/v1/scores
Content-Type: application/json
X-Game-Key: gk_xxxxxxxxxxxxxxxxxxxxxxxx
X-Timestamp: 1767225600
X-Signature: hex( HMAC-SHA256( secret, "{X-Timestamp}.{raw JSON body}" ) )
{
"player_id": "8a3f2c1e-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
"player_name": "Squirrel",
"board": "level-12",
"value": 34,
"moves": 51,
"platform": "ios",
"app_version": "1.7"
}
You can also post to /api/v1/games/{slug}/scores (the slug identifies the game; X-Game-Key is then optional but must match if sent).
value is a whole number in the board's unit (seconds for times). moves is optional and breaks ties (fewer is better). platform is one of ios, android, web, other.
Response (201 for a new personal best, 200 otherwise):
{ "board": "level-12", "player_name": "Squirrel", "is_new_best": true,
"best": { "value": 34, "display": "0:34", "moves": 51 },
"rank": 7, "total": 240 }
Only the player's best result per board is kept. The name actually stored is returned in player_name (unsuitable names are replaced).
3. Read a leaderboard
GET https://scoreperch.com/api/v1/games/{slug}/leaderboards/{board}?limit=50&player_id={uuid}
{ "board": { "key": "level-12", "name": "Level 12", "sort": "asc", "unit": "seconds" },
"entries": [ { "rank": 1, "name": "Ana", "value": 21, "display": "0:21", "moves": 40, "date": "2026-11-03" } ],
"you": { "rank": 7, "name": "Squirrel", "value": 34, "display": "0:34", "moves": 51, "date": "2026-11-03" },
"total": 240 }
GET /api/v1/games/{slug}/boards lists the boards. Each game also has a public page at /games/{slug} you can open from your game, e.g. /games/{slug}?board=level-12.
4. Rotating the secret
If a secret leaks, use Regenerate secret in the dashboard. The old secret keeps working for 7 days, so players on older versions of your game can still post while you release an update with the new one.
5. Errors
401 stale_request: the timestamp is more than 5 minutes off; use the device clock in UTC seconds.401 bad_signature: the signature doesn't match (sign the exact bytes you send).409 replayed_request: the same signed request was sent twice.404 game_not_found: wrong slug or Game Key, or the game is switched off.404 board_not_found,422 value_out_of_range,403 player_banned.429: too many requests (30 posts per minute per address, 600 per minute per game).
6. Fair play & privacy
The secret ships inside your game, so signing deters casual cheating but can't stop a determined attacker. Boards have minimum and maximum values, and we remove impossible scores. Never send real names, emails or device identifiers; list ScorePerch in your privacy policy — the generated privacy page does this for you. See the Terms for developers.