🎁 Hulppieten Leaderboard API

Two endpoints. No auth. Plain JSON.

Leaderboard for the Hulppieten Game - the client calls this directly over HTTPS.

POST /submit-score
{
  "playerId": "<uuid you generate once>",
  "nickname": "jonathan",
  "score": 12,
  "timeMs": 61500
}

→ 200
{ "improved": true, "bestScore": 12,
  "bestTimeMs": 61500, "rank": 87 }
GET /leaderboard?playerId=<uuid>
→ 200
{
  "entries": [ /* top 50, ranked */ ],
  "me": {
    "rank": 87, "nickname": "jonathan",
    "score": 12, "timeMs": 61500
  },
  "totalPlayers": 4812
}
1 · Best round countsThe server keeps each player's best result - submit every round, read improved.
2 · Names are uniqueTaken by someone else? 409 - the player types a different name, resubmit the same round.
3 · Careful retriesOnly 5xx/network (once) and 429 after retry-after. Never drop a played round.

Identity: playerId vs nickname - read this once

playerId is the identity. A UUID v4 supplied by the client - the server never issues IDs and players never see them. How you generate and store it is your choice, but it must be stable (the same value every time that player plays) and anonymous (never an account id, device id or anything identifying a person - the board is public and the audience is children). The nickname is only the display name attached to that playerId: chosen by the player, unique on the board (case-insensitive), profanity-filtered.

The nickname needs no local storage: GET /leaderboard?playerId=… returns me.nickname for a known player, so you can recover it at startup and only have to ask for a name when me is absent. On repeat plays you may omit nickname entirely and the stored name is used.

you submit…result
new playerId + a free nicknameplayer created (a name is required the first time)
known playerId, no nickname (omit / null / "")stored name is used - the normal repeat play
known playerId + their own namenormal repeat play
known playerId + a different free namerename; the old name becomes available again
any playerId + a name held by another player409 nickname_taken - nothing stored; ask for a new name, resubmit the same round
new playerId, no nickname400 nickname_required
All error codes
codeswhat you do
bad_nickname · nickname_not_allowed · nickname_required (400) · nickname_taken (409) new name, same round, resubmit
rate_limited (429) · internal (500) · network wait / retry once, keep the round
bad_body · bad_player_id · bad_score · bad_time (400) · payload_too_large (413) · rejected (422) log, never retry
board_full (503) anti-abuse cap - "try again later", keep the round
Field rules & limits
playerIdUUID v4 - the player's identity, supplied by the client. Stable per player, anonymous, never an account id
nickname3-16 letters/digits (accents OK, no spaces) · unique, case-insensitive · profanity-filtered · optional on repeat plays (stored name is used)
scoreinteger 0-999
timeMsplay time in ms · tiebreaker, lower wins · plausible range (now 1 s-10 min)
rate limitsper player: 10 submits/min, 60 reads/min → 429 · anonymous board cached 5 s

Playground

Try it against the live dev API. Each simulated player behaves like one phone.

Players

A player = one device. The playerId is the identity; the nickname is only the display name attached to it - see "Identity" above. Add a second player to test name conflicts.

Submit a round

Exactly what the client sends when a round ends.

Request body

            
          
Error scenarios
Submits with the other player's name. Type a different name and submit again - same round, exactly as the client should.
Sanity filter (profanity/leetspeak, reserved words, 8+ digit runs) - and a brand-new player without a name.
Format validation - nothing is stored; a client should never send these.
Rate limiter (10 submits/min, approximate) and an unknown route.

Leaderboard

Rendered with the documented rules: your row highlighted in the top 50, or appended below with its global rank.

Request log

Newest first - status, latency, bodies, copy-as-curl.