🎁 Hulppieten Leaderboard API

Two endpoints. No auth. Plain JSON.

Leaderboard for the Hulppieten Game lens - the lens 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.
⚠️ Camera Kit allowlist - before testing on a device

Both hosts must be allowlisted in the My Lenses portal (My APIs → "Provided Processor"). Lens Studio's preview does not enforce this - a Camera Kit app does, and a blocked host shows up as a thrown fetch error, not an HTTP status.

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 - generate once, store on the device (this is the player's identity)
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 = a stable playerId + its nickname, kept in your browser. Add a second one to test name conflicts.

Submit a round

Exactly what the lens 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, like the lens.
Sanity filter (profanity/leetspeak, reserved words, 8+ digit runs) - and a brand-new player without a name.
Format validation - nothing is stored; a lens should never send these.
Rate limiter (10 submits/min, approximate) and an unknown route.

Leaderboard

Rendered with the lens's 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.