{"info":{"name":"2048 Cloud API v2.1.0","description":"Accounts, cross-device saves, leaderboards, achievements, and statistics for the 2048 game.","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json"},"variable":[{"key":"baseUrl","value":"https://game-2048-cloud-api.vercel.app"},{"key":"accessToken","value":""}],"item":[{"name":"Meta","item":[{"name":"Liveness","request":{"method":"GET","description":"Answers whether the process is running. It deliberately does **not** touch the database: a health check that fails because a dependency is slow invites a platform to restart a service that was fine. Use `/ready` for the dependency question.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/health","host":["{{baseUrl}}"],"path":["api","v1","health"],"query":[]}}},{"name":"Readiness, including a database ping","request":{"method":"GET","description":"Readiness, including a database ping","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/ready","host":["{{baseUrl}}"],"path":["api","v1","ready"],"query":[]}}},{"name":"Build and runtime versions","request":{"method":"GET","description":"Build and runtime versions","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/version","host":["{{baseUrl}}"],"path":["api","v1","version"],"query":[]}}},{"name":"Public client configuration","request":{"method":"GET","description":"Feature flags and limits, read once at start-up so clients do not hard-code values the server also enforces.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/config","host":["{{baseUrl}}"],"path":["api","v1","config"],"query":[]}}},{"name":"Request counters for this instance","request":{"method":"GET","description":"Counters belong to one warm serverless instance and reset when it recycles. They are not fleet-wide totals.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/metrics","host":["{{baseUrl}}"],"path":["api","v1","metrics"],"query":[]}}},{"name":"The same counters in Prometheus exposition format","request":{"method":"GET","description":"The same counters in Prometheus exposition format","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/metrics.prom","host":["{{baseUrl}}"],"path":["api","v1","metrics.prom"],"query":[]}}}]},{"name":"Authentication","item":[{"name":"Create an account","request":{"method":"POST","description":"Returns a token pair immediately, so a player who signs up mid-round can sync without a second request.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/register","host":["{{baseUrl}}"],"path":["api","v1","auth","register"],"query":[]}}},{"name":"Sign in","request":{"method":"POST","description":"An unknown account and a wrong password return the same error, so this endpoint cannot be used to discover who has an account.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/login","host":["{{baseUrl}}"],"path":["api","v1","auth","login"],"query":[]}}},{"name":"Rotate a token pair","request":{"method":"POST","description":"Refresh tokens are single-use. Replaying a rotated token revokes the whole session, which is what turns a stolen token into a detectable event rather than a silent one.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/refresh","host":["{{baseUrl}}"],"path":["api","v1","auth","refresh"],"query":[]}}},{"name":"Revoke one session","request":{"method":"POST","description":"Revoke one session","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/logout","host":["{{baseUrl}}"],"path":["api","v1","auth","logout"],"query":[]}}},{"name":"Revoke every session on the account","request":{"method":"POST","description":"Revoke every session on the account","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/auth/logout-all","host":["{{baseUrl}}"],"path":["api","v1","auth","logout-all"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"The signed-in account","request":{"method":"GET","description":"The signed-in account","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/auth/me","host":["{{baseUrl}}"],"path":["api","v1","auth","me"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Update profile fields","request":{"method":"PATCH","description":"Update profile fields","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/me","host":["{{baseUrl}}"],"path":["api","v1","auth","me"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Delete the account and every trace of it","request":{"method":"DELETE","description":"Removes the account, its sessions, saves, scores, achievements, follows, and telemetry in one request. There is no tombstone and no recovery window.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/me","host":["{{baseUrl}}"],"path":["api","v1","auth","me"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Change the password","request":{"method":"POST","description":"By default every other session is revoked, because a password change that leaves other devices signed in is not a password change.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/change-password","host":["{{baseUrl}}"],"path":["api","v1","auth","change-password"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Reset a forgotten password","request":{"method":"POST","description":"Interim recovery path with no email round trip: a matching username and email address are enough to set a new password, and every session on the account is revoked. Knowing both is therefore account takeover, so this is gated behind `FEATURE_PASSWORD_RESET` and the auth rate limiter, and answers identically whichever half is wrong. Replace with a mailed single-use token before relying on it.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/auth/reset-password","host":["{{baseUrl}}"],"path":["api","v1","auth","reset-password"],"query":[]}}},{"name":"List signed-in devices","request":{"method":"GET","description":"List signed-in devices","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/auth/sessions","host":["{{baseUrl}}"],"path":["api","v1","auth","sessions"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Revoke one device","request":{"method":"DELETE","description":"Revoke one device","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/auth/sessions/{sessionId}","host":["{{baseUrl}}"],"path":["api","v1","auth","sessions","{sessionId}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Check whether a username or email is free","request":{"method":"GET","description":"Intended for inline validation on a sign-up form. The unique indexes remain the real guarantee; this is a better error message, not the enforcement.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/auth/available","host":["{{baseUrl}}"],"path":["api","v1","auth","available"],"query":[{"key":"username","value":"","description":"Username to test.","disabled":true},{"key":"email","value":"","description":"Email address to test.","disabled":true}]}}}]},{"name":"Players","item":[{"name":"Search players","request":{"method":"GET","description":"Matching is an anchored prefix on the username so the query uses an index rather than scanning the collection on every keystroke.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/users","host":["{{baseUrl}}"],"path":["api","v1","users"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false},{"key":"q","value":"","description":"Username prefix.","disabled":true},{"key":"sort","value":"best","description":"Ordering.","disabled":false}]}}},{"name":"Read preferences","request":{"method":"GET","description":"Read preferences","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/users/me/preferences","host":["{{baseUrl}}"],"path":["api","v1","users","me","preferences"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Update preferences","request":{"method":"PUT","description":"Update preferences","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/users/me/preferences","host":["{{baseUrl}}"],"path":["api","v1","users","me","preferences"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Download everything stored about the account","request":{"method":"GET","description":"The counterpart to account deletion: data about a player should be theirs to read as well as theirs to remove.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/users/me/export","host":["{{baseUrl}}"],"path":["api","v1","users","me","export"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"A public profile","request":{"method":"GET","description":"A public profile","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/users/{username}","host":["{{baseUrl}}"],"path":["api","v1","users","{username}"],"query":[]}}},{"name":"A player's best rounds","request":{"method":"GET","description":"A player's best rounds","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/users/{username}/scores","host":["{{baseUrl}}"],"path":["api","v1","users","{username}","scores"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false}]}}},{"name":"A player's achievements","request":{"method":"GET","description":"A player's achievements","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/users/{username}/achievements","host":["{{baseUrl}}"],"path":["api","v1","users","{username}","achievements"],"query":[]}}},{"name":"A player's statistics","request":{"method":"GET","description":"A player's statistics","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/users/{username}/stats","host":["{{baseUrl}}"],"path":["api","v1","users","{username}","stats"],"query":[]}}}]},{"name":"Cloud saves","item":[{"name":"List every slot","request":{"method":"GET","description":"List every slot","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/saves","host":["{{baseUrl}}"],"path":["api","v1","saves"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Delete every slot","request":{"method":"DELETE","description":"Delete every slot","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/saves","host":["{{baseUrl}}"],"path":["api","v1","saves"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Two-way synchronisation","request":{"method":"POST","description":"The endpoint to call on launch, on sign-in, and on reconnect — the only one that can reconcile two devices without losing a round.\n\nResolution order: no remote save uploads the local one; no local save downloads the remote one; identical rounds report `in_sync`; a local save carrying a `baseRevision` at or above the stored revision is a continuation and uploads; otherwise the further round (score, then moves) wins and **the other is preserved in a `conflict-…` slot**. Nothing is discarded.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/saves/sync","host":["{{baseUrl}}"],"path":["api","v1","saves","sync"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Read the active round","request":{"method":"GET","description":"Read the active round","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/saves/current","host":["{{baseUrl}}"],"path":["api","v1","saves","current"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Overwrite the active round","request":{"method":"PUT","description":"Unconditional: the caller's save wins. Use `POST /saves/sync` unless the player has explicitly chosen this device's round.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/saves/current","host":["{{baseUrl}}"],"path":["api","v1","saves","current"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Read a slot","request":{"method":"GET","description":"Read a slot","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/saves/{slot}","host":["{{baseUrl}}"],"path":["api","v1","saves","{slot}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Create or overwrite a slot","request":{"method":"PUT","description":"Create or overwrite a slot","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/saves/{slot}","host":["{{baseUrl}}"],"path":["api","v1","saves","{slot}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Delete a slot","request":{"method":"DELETE","description":"Delete a slot","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/saves/{slot}","host":["{{baseUrl}}"],"path":["api","v1","saves","{slot}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}}]},{"name":"Scores","item":[{"name":"Submit a finished round","request":{"method":"POST","description":"Idempotent: the same board and score from the same player returns the original row with `duplicate: true` and a 200 rather than creating a second leaderboard entry, so a retry after a flaky network is safe.\n\nA score that exceeds what its final board could have produced is stored with `verified: false` and kept out of every leaderboard. It is flagged rather than refused, because refusing would lose a genuine round to a client bug.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/scores","host":["{{baseUrl}}"],"path":["api","v1","scores"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"The signed-in player's rounds","request":{"method":"GET","description":"The signed-in player's rounds","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/scores","host":["{{baseUrl}}"],"path":["api","v1","scores"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false},{"key":"mode","value":"all","description":"Filter by mode.","disabled":false},{"key":"sort","value":"recent","description":"Ordering.","disabled":false},{"key":"wonOnly","value":"false","description":"Only rounds that reached 2048.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Personal best","request":{"method":"GET","description":"Personal best","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/scores/best","host":["{{baseUrl}}"],"path":["api","v1","scores","best"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Career statistics","request":{"method":"GET","description":"Career statistics","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/scores/stats","host":["{{baseUrl}}"],"path":["api","v1","scores","stats"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"One round, with its final board","request":{"method":"GET","description":"One round, with its final board","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/scores/{id}","host":["{{baseUrl}}"],"path":["api","v1","scores","{id}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Delete a round","request":{"method":"DELETE","description":"Career totals are intentionally left alone: they record rounds played, and making `gamesPlayed` go down because a row was removed is not what anyone expects.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/scores/{id}","host":["{{baseUrl}}"],"path":["api","v1","scores","{id}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}}]},{"name":"Leaderboard","item":[{"name":"A ranked page","request":{"method":"GET","description":"One row per player — their best qualifying round in the window, never three of the same player's games in the top ten. Ties break by the earlier submission, so a player's rank does not drift between two identical requests.\n\nAuthenticated requests mark the viewer's own row with `isViewer` and are never shared-cached.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/leaderboard","host":["{{baseUrl}}"],"path":["api","v1","leaderboard"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false},{"key":"period","value":"all","description":"Window to rank within. All windows are UTC; `GET /leaderboard/periods` returns the exact boundaries.","disabled":false},{"key":"mode","value":"classic","description":"Which board to read.","disabled":false},{"key":"challengeDate","value":"","description":"For `mode=daily`, the challenge date.","disabled":true}]}}},{"name":"The exact UTC boundaries of every window","request":{"method":"GET","description":"The exact UTC boundaries of every window","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/leaderboard/periods","host":["{{baseUrl}}"],"path":["api","v1","leaderboard","periods"],"query":[]}}},{"name":"The signed-in player's rank","request":{"method":"GET","description":"The signed-in player's rank","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/leaderboard/me","host":["{{baseUrl}}"],"path":["api","v1","leaderboard","me"],"query":[{"key":"period","value":"all","description":"Window to rank within. All windows are UTC; `GET /leaderboard/periods` returns the exact boundaries.","disabled":false},{"key":"mode","value":"classic","description":"Which board to read.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"The slice of the board around the player","request":{"method":"GET","description":"The slice of the board around the player","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/leaderboard/around-me","host":["{{baseUrl}}"],"path":["api","v1","leaderboard","around-me"],"query":[{"key":"period","value":"all","description":"Window to rank within. All windows are UTC; `GET /leaderboard/periods` returns the exact boundaries.","disabled":false},{"key":"mode","value":"classic","description":"Which board to read.","disabled":false},{"key":"radius","value":"4","description":"Rows either side.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"A board of the people the player follows","request":{"method":"GET","description":"A board of the people the player follows","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/leaderboard/friends","host":["{{baseUrl}}"],"path":["api","v1","leaderboard","friends"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false},{"key":"period","value":"all","description":"Window to rank within. All windows are UTC; `GET /leaderboard/periods` returns the exact boundaries.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Any player's rank","request":{"method":"GET","description":"Any player's rank","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/leaderboard/users/{username}","host":["{{baseUrl}}"],"path":["api","v1","leaderboard","users","{username}"],"query":[{"key":"period","value":"all","description":"Window to rank within. All windows are UTC; `GET /leaderboard/periods` returns the exact boundaries.","disabled":false},{"key":"mode","value":"classic","description":"Which board to read.","disabled":false}]}}}]},{"name":"Achievements","item":[{"name":"The catalog","request":{"method":"GET","description":"Definitions are compiled into the build, so this changes only on deploy and is cached for an hour.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/achievements","host":["{{baseUrl}}"],"path":["api","v1","achievements"],"query":[]}}},{"name":"Progress for the signed-in player","request":{"method":"GET","description":"Progress for the signed-in player","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/achievements/me","host":["{{baseUrl}}"],"path":["api","v1","achievements","me"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"One definition","request":{"method":"GET","description":"One definition","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/achievements/{key}","host":["{{baseUrl}}"],"path":["api","v1","achievements","{key}"],"query":[]}}}]},{"name":"Statistics","item":[{"name":"Service-wide totals","request":{"method":"GET","description":"Service-wide totals","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/stats/global","host":["{{baseUrl}}"],"path":["api","v1","stats","global"],"query":[]}}},{"name":"How far rounds get","request":{"method":"GET","description":"The share of rounds ending at each highest tile — the clearest single picture of the difficulty curve.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/stats/tiles","host":["{{baseUrl}}"],"path":["api","v1","stats","tiles"],"query":[]}}},{"name":"A dense daily series","request":{"method":"GET","description":"Days with no games appear as zeroes rather than being omitted, so the series can be charted without silently rewriting the x-axis.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/stats/activity","host":["{{baseUrl}}"],"path":["api","v1","stats","activity"],"query":[{"key":"days","value":"30","description":"Length of the window.","disabled":false}]}}},{"name":"The signed-in player's statistics","request":{"method":"GET","description":"The signed-in player's statistics","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/stats/me","host":["{{baseUrl}}"],"path":["api","v1","stats","me"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"The signed-in player's daily series","request":{"method":"GET","description":"The signed-in player's daily series","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/stats/me/activity","host":["{{baseUrl}}"],"path":["api","v1","stats","me","activity"],"query":[{"key":"days","value":"30","description":"Length of the window.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}}]},{"name":"Social","item":[{"name":"Follow a player","request":{"method":"POST","description":"Idempotent: following twice succeeds rather than returning a duplicate-key error the client has to special-case.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/social/follow/{username}","host":["{{baseUrl}}"],"path":["api","v1","social","follow","{username}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Unfollow a player","request":{"method":"DELETE","description":"Unfollow a player","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/social/follow/{username}","host":["{{baseUrl}}"],"path":["api","v1","social","follow","{username}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Who the player follows","request":{"method":"GET","description":"Who the player follows","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/social/following","host":["{{baseUrl}}"],"path":["api","v1","social","following"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Who follows the player","request":{"method":"GET","description":"Who follows the player","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/social/followers","host":["{{baseUrl}}"],"path":["api","v1","social","followers"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"The edge between two players","request":{"method":"GET","description":"The edge between two players","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/social/relationship/{username}","host":["{{baseUrl}}"],"path":["api","v1","social","relationship","{username}"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Players worth following","request":{"method":"GET","description":"Strong players the viewer does not already follow. The heuristic is deliberately that simple.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/social/suggestions","host":["{{baseUrl}}"],"path":["api","v1","social","suggestions"],"query":[{"key":"limit","value":"10","description":"How many.","disabled":false}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}}]},{"name":"Daily challenge","item":[{"name":"Today's challenge","request":{"method":"GET","description":"The board is *derived* from the date with a seeded generator, not stored, so every client gets the same opening position and can reproduce it offline from the seed alone.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/challenges/daily","host":["{{baseUrl}}"],"path":["api","v1","challenges","daily"],"query":[]}}},{"name":"The board for one day","request":{"method":"GET","description":"The board for one day","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/challenges/daily/leaderboard","host":["{{baseUrl}}"],"path":["api","v1","challenges","daily","leaderboard"],"query":[{"key":"limit","value":"25","description":"Page size.","disabled":false},{"key":"offset","value":"0","description":"Rows to skip.","disabled":false},{"key":"date","value":"","description":"Defaults to today (UTC).","disabled":true}]}}},{"name":"The player's rank in a day's challenge","request":{"method":"GET","description":"The player's rank in a day's challenge","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/challenges/daily/me","host":["{{baseUrl}}"],"path":["api","v1","challenges","daily","me"],"query":[{"key":"date","value":"","description":"Defaults to today (UTC).","disabled":true}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Submit today's attempt","request":{"method":"POST","description":"Only today's challenge accepts submissions. Without that rule the daily board becomes a backlog anyone can grind through.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/challenges/daily/submit","host":["{{baseUrl}}"],"path":["api","v1","challenges","daily","submit"],"query":[]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{accessToken}}"}]}}},{"name":"Any day's challenge","request":{"method":"GET","description":"Any day's challenge","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/challenges/daily/{date}","host":["{{baseUrl}}"],"path":["api","v1","challenges","daily","{date}"],"query":[]}}}]},{"name":"Telemetry","item":[{"name":"Record gameplay events","request":{"method":"POST","description":"Coarse, opt-in, pseudonymous, and closed-vocabulary: both the event types and the metadata keys are enumerated, so this cannot become a general sink or accidentally carry a board. Rows expire after 90 days. See `docs/privacy.md`.","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":{"raw":"{{baseUrl}}/api/v1/events","host":["{{baseUrl}}"],"path":["api","v1","events"],"query":[]}}},{"name":"Event counts by type and client","request":{"method":"GET","description":"Event counts by type and client","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Client","value":"cli"}],"url":{"raw":"{{baseUrl}}/api/v1/events/summary","host":["{{baseUrl}}"],"path":["api","v1","events","summary"],"query":[{"key":"days","value":"7","description":"Window length.","disabled":false}]}}}]}]}