Skip to content

A backend with server keys

A server key lets your backend act for your site on /v1/server/*: create a Filudi player for each of your users, give the browser a token for that player, read leaderboards with nicknames, read the site’s numbers. The key never reaches a browser and nothing else of the API takes it.

Create a key in the console, under the site, Keys: a name and the scopes it needs. The answer shows the key once, fsk_<site slug>_<32 base62 characters>; the API keeps a hash and the console shows the first 12 characters from then on. Store it in your backend’s environment. Only an approved site has keys, 20 at most, revoked ones included.

ScopeRoutes
catalogGET /v1/server/catalog
playersPOST /v1/server/players, GET /v1/server/players/{playerId}
tokensPOST /v1/server/players/{playerId}/tokens, POST /v1/server/game-tokens
leaderboardsGET /v1/server/leaderboards/{gameId}/{board}
statsGET /v1/server/stats/overview, GET /v1/server/stats/games/{gameId}

A key without the scope of a route answers 403, as does a revoked key or a key of a site that lost its approval; message says which. 600 requests a minute per key, then 429 with Retry-After. No IP limit, no CORS. Revoke a key from the console: the row stays with revokedAt and every call with it answers 403 from then on.

Create a key

Terminal window
curl -X POST 'https://api.filudi.com/v1/admin/sites/00000000-0000-0000-0000-000000000000/keys' \
-b "filudi_console=$FILUDI_SESSION" \
-H 'origin: https://developers.filudi.com' \
-H 'content-type: application/json' \
-d '{ "name": "string", "scopes": ["players", "tokens", "leaderboards"] }'

POST /v1/server/players { externalId, nickname?, locale? } creates a player for one of your users, or finds the one created before: externalId is unique per site, so the call is safe to repeat. A new player answers 201, an existing one 200. A player created here is a guest with no token until you ask for one. nickname and locale apply on creation only; the player changes them later with their own token on PATCH /v1/sdk/players/me.

GET /v1/server/players/{playerId} reads the profile, the saves metadata and the best scores. A player of another site answers 404.

Find or create a player

Terminal window
curl -X POST 'https://api.filudi.com/v1/server/players' \
-H "authorization: Bearer $FILUDI_SITE_KEY" \
-H 'content-type: application/json' \
-d '{ "externalId": "string", "nickname": "Pebble", "locale": "en" }'

The page needs a player token to run a game as filudi.com does. POST /v1/server/players/{playerId}/tokens answers an fp1 token, the same kind POST /v1/sdk/players answers in the browser. Give it to the page over your own authenticated channel: the answer of your sign-in, a page you render for a signed-in user, a short fetch on your origin. Never in a URL, never in a cookie readable by scripts of other origins.

In the page, the token goes where a guest token would: localStorage under filudi:player:<site>, then PlayerClient or your own code uses it. The page exchanges it for a game token before each frame, as any front does. A backend that renders the whole page can skip that step too: POST /v1/server/game-tokens { playerId, game } answers the fg1 token for the frame, and the page posts it in filudi:init without holding the player token at all.

A token for the browser

Terminal window
curl -X POST 'https://api.filudi.com/v1/server/players/00000000-0000-0000-0000-000000000000/tokens' \
-H "authorization: Bearer $FILUDI_SITE_KEY"

The whole exchange, from your user’s sign-in to the game calling the API:

Sequence of a backend with a server keyThe browser signs in to your backend. Your backend creates or finds the Filudi player by externalId, asks for a player token, and sends it to the browser. The browser exchanges it for a game token and posts filudi:init to the game frame, which then calls the Filudi API with that game token.BrowserYour backendFiludi APIGame framesigns in to your sitePOST /v1/server/playersplayer idPOST /v1/server/players/[id]/tokensfp1 player tokentoken in your own responsePOST /v1/sdk/game-tokensfg1 game tokenfiludi:init with the fg1 tokensaves, scores, events

Dashed arrows are answers. Solid ones are calls. The server key travels only on the arrows that leave your backend; the player token never leaves the browser; the frame sees the game token alone.

GET /v1/server/leaderboards/{gameId}/{board}?period=week&limit=10 answers the same shape as the browser route, with the nickname of each player. isMe is always false: a server has no “me”. Use it for a page rendered on the server, a Discord bot, a weekly email. The browser route stays the one to use inside a page, where the player’s own entry matters.

Weekly top

Terminal window
curl 'https://api.filudi.com/v1/server/leaderboards/gloop/height?period=week&limit=10' \
-H "authorization: Bearer $FILUDI_SITE_KEY"

GET /v1/server/stats/overview?from&to and GET /v1/server/stats/games/{gameId}?from&to answer what the console shows for the site: the same shapes as the admin routes, cached 60 seconds, 400 days at most. Statistics lists the fields.

  • Store a player token. It has no expiry and opens the player’s account; it belongs in the player’s browser. Ask for a new one on each sign-in instead.
  • Act on a player’s saves or scores. Saves and scores are written by the game, in the browser, with a game token; the API signs scores per play session and a server cannot forge that signature.
  • Call /v1/admin/*. The console API takes a session cookie, not a key. Automation of the console is not offered in this release.
  • Reach players of another site, or of filudi.com. A player id from your site means nothing elsewhere.