Two endpoints. No auth. Plain JSON.
Leaderboard for the Hulppieten Game - the client calls this directly over HTTPS.
{
"playerId": "<uuid you generate once>",
"nickname": "jonathan",
"score": 12,
"timeMs": 61500
}
→ 200
{ "improved": true, "bestScore": 12,
"bestTimeMs": 61500, "rank": 87 }
→ 200
{
"entries": [ /* top 50, ranked */ ],
"me": {
"rank": 87, "nickname": "jonathan",
"score": 12, "timeMs": 61500
},
"totalPlayers": 4812
}
improved.409 - the player types a different name, resubmit the same round.5xx/network (once) and 429 after retry-after. Never drop a played round.
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 nickname | player 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 name | normal repeat play |
| known playerId + a different free name | rename; the old name becomes available again |
| any playerId + a name held by another player | 409 nickname_taken - nothing stored; ask for a new name, resubmit the same round |
| new playerId, no nickname | 400 nickname_required |
| codes | what 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 |
playerId | UUID v4 - the player's identity, supplied by the client. Stable per player, anonymous, never an account id |
nickname | 3-16 letters/digits (accents OK, no spaces) · unique, case-insensitive · profanity-filtered · optional on repeat plays (stored name is used) |
score | integer 0-999 |
timeMs | play time in ms · tiebreaker, lower wins · plausible range (now 1 s-10 min) |
| rate limits | per player: 10 submits/min, 60 reads/min → 429 · anonymous board cached 5 s |
dev base URL: https://hulppieten-game-api-dev.intertoys-kidshq.nl
· contract for your own tooling: openapi.yaml
Try it against the live dev API. Each simulated player behaves like one phone.
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.
Not a valid UUID - change not saved.
Exactly what the client sends when a round ends.
Rendered with the documented rules: your row highlighted in the top 50, or appended below with its global rank.
Newest first - status, latency, bodies, copy-as-curl.