Server routes
Routes for portal backends, authenticated by a site key (ADR 0015). Generated from openapi.yaml of games-api 0.7.0: 8 routes.
GET /v1/server/catalog: The site’s catalogPOST /v1/server/players: Create or find a player by your own user idGET /v1/server/players/{playerId}: Profile, saves metadata and best scores of one of the site’s playersPOST /v1/server/players/{playerId}/tokens: A player token for that player’s browserPOST /v1/server/game-tokens: A game token for a player and a gameGET /v1/server/leaderboards/{gameId}/{board}: Top entries with nicknamesGET /v1/server/stats/overview: The site’s numbers for a range of UTC daysGET /v1/server/stats/games/{gameId}: One game’s numbers on the site for a range of UTC days
GET /v1/server/catalog
curl 'https://api.filudi.com/v1/server/catalog' \ -H "authorization: Bearer $FILUDI_SITE_KEY"// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/catalog', { headers: { authorization: `Bearer ${siteKey}` },});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.get( 'https://api.filudi.com/v1/server/catalog', headers={'authorization': f'Bearer {site_key}'},)response.raise_for_status()data = response.json()The site’s catalog
Scope catalog. Same shape as GET /v1/catalog/{site} for the key’s site, with Cache-Control: private, max-age=60.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope catalog.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
locale | query | string | no | Returns texts for one locale only; default returns every locale of the site |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 200 | Catalog | Catalog. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 429 | Error | Too many requests. Headers: Retry-After. |
POST /v1/server/players
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": "string", "locale": "en"}'// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/players', { method: 'POST', headers: { authorization: `Bearer ${siteKey}`, 'content-type': 'application/json' }, body: JSON.stringify({ externalId: 'string', nickname: 'string', locale: 'en', }),});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.post( 'https://api.filudi.com/v1/server/players', headers={'authorization': f'Bearer {site_key}'}, json={ 'externalId': 'string', 'nickname': 'string', 'locale': 'en', },)response.raise_for_status()data = response.json()Create or find a player by your own user id
Scope players. externalId is unique per site: an existing player answers 200, a new one 201. A player
created here is a guest with no token until POST /v1/server/players/{playerId}/tokens. nickname and
locale are applied on creation only; change them later with the player token on PATCH /v1/sdk/players/me.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope players.
Request body
Section titled “Request body”application/json, required. The body is a ServerPlayerInput.
| Property | Type | Required | Description |
|---|---|---|---|
externalId | string | yes | Your own user id; 1 to 128 characters |
nickname | string | no | 3 to 20 characters; pattern ^[\p{L}\p{N} _.-]+$ |
locale | string | no | Defaults to the site’s first locale |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 200 | ServerPlayer | Existing player. |
| 201 | ServerPlayer | Created. |
| 400 | Error | Validation failed. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 429 | Error | Too many requests. Headers: Retry-After. |
GET /v1/server/players/{playerId}
curl 'https://api.filudi.com/v1/server/players/00000000-0000-0000-0000-000000000000' \ -H "authorization: Bearer $FILUDI_SITE_KEY"// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/players/00000000-0000-0000-0000-000000000000', { headers: { authorization: `Bearer ${siteKey}` },});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.get( 'https://api.filudi.com/v1/server/players/00000000-0000-0000-0000-000000000000', headers={'authorization': f'Bearer {site_key}'},)response.raise_for_status()data = response.json()Profile, saves metadata and best scores of one of the site’s players
Scope players. 404 for a player of another site.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope players.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
playerId | path | string (uuid) | yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 200 | PlayerAdmin | Player. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 404 | Error | Unknown resource. |
| 429 | Error | Too many requests. Headers: Retry-After. |
POST /v1/server/players/{playerId}/tokens
curl -X POST 'https://api.filudi.com/v1/server/players/00000000-0000-0000-0000-000000000000/tokens' \ -H "authorization: Bearer $FILUDI_SITE_KEY"// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/players/00000000-0000-0000-0000-000000000000/tokens', { method: 'POST', headers: { authorization: `Bearer ${siteKey}` },});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.post( 'https://api.filudi.com/v1/server/players/00000000-0000-0000-0000-000000000000/tokens', headers={'authorization': f'Bearer {site_key}'},)response.raise_for_status()data = response.json()A player token for that player’s browser
Scope tokens. An fp1 token, as POST /v1/sdk/players answers, so your page runs GameFrame or the SDK
as filudi.com does. Hand it to the browser over your own authenticated channel.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope tokens.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
playerId | path | string (uuid) | yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 201 | object | Token. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 404 | Error | Unknown resource. |
| 429 | Error | Too many requests. Headers: Retry-After. |
Body of 201
| Property | Type | Required | Description |
|---|---|---|---|
token | string | yes |
POST /v1/server/game-tokens
curl -X POST 'https://api.filudi.com/v1/server/game-tokens' \ -H "authorization: Bearer $FILUDI_SITE_KEY" \ -H 'content-type: application/json' \ -d '{ "playerId": "00000000-0000-0000-0000-000000000000", "game": "gloop"}'// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/game-tokens', { method: 'POST', headers: { authorization: `Bearer ${siteKey}`, 'content-type': 'application/json' }, body: JSON.stringify({ playerId: '00000000-0000-0000-0000-000000000000', game: 'gloop', }),});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.post( 'https://api.filudi.com/v1/server/game-tokens', headers={'authorization': f'Bearer {site_key}'}, json={ 'playerId': '00000000-0000-0000-0000-000000000000', 'game': 'gloop', },)response.raise_for_status()data = response.json()A game token for a player and a game
Scope tokens. The same token as POST /v1/sdk/game-tokens answers (ADR 0013), without the player’s own token.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope tokens.
Request body
Section titled “Request body”application/json, required.
| Property | Type | Required | Description |
|---|---|---|---|
playerId | string (uuid) | yes | |
game | string | yes | Game slug |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 201 | GameToken | Game token. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 404 | none | Unknown player on this site, or the game is not on the site catalog. |
| 429 | Error | Too many requests. Headers: Retry-After. |
GET /v1/server/leaderboards/{gameId}/{board}
curl 'https://api.filudi.com/v1/server/leaderboards/gloop/height' \ -H "authorization: Bearer $FILUDI_SITE_KEY"// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/leaderboards/gloop/height', { headers: { authorization: `Bearer ${siteKey}` },});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.get( 'https://api.filudi.com/v1/server/leaderboards/gloop/height', headers={'authorization': f'Bearer {site_key}'},)response.raise_for_status()data = response.json()Top entries with nicknames
Scope leaderboards. Same answer as GET /v1/sdk/leaderboards/{gameId}/{board}; isMe is always false.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope leaderboards.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
gameId | path | string | yes | Game slug |
board | path | string | yes | pattern ^[a-z][a-z0-9_]{0,31}$ |
period | query | one of "day", "week", "all" | no | default "all" |
limit | query | integer | no | 1 to 50; default 10 |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 200 | LeaderboardTop | Top entries. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 404 | Error | Unknown resource. |
| 429 | Error | Too many requests. Headers: Retry-After. |
GET /v1/server/stats/overview
curl 'https://api.filudi.com/v1/server/stats/overview?from=2026-10-30&to=2026-10-30' \ -H "authorization: Bearer $FILUDI_SITE_KEY"// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/stats/overview?from=2026-10-30&to=2026-10-30', { headers: { authorization: `Bearer ${siteKey}` },});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.get( 'https://api.filudi.com/v1/server/stats/overview?from=2026-10-30&to=2026-10-30', headers={'authorization': f'Bearer {site_key}'},)response.raise_for_status()data = response.json()The site’s numbers for a range of UTC days
Scope stats. Same answer and range rules as GET /v1/admin/sites/{siteId}/stats/overview.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope stats.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
from | query | string (date) | yes | First UTC day, included |
to | query | string (date) | yes | Last UTC day, included |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 200 | StatsOverview | Overview. |
| 400 | none | Range over 400 days, or to before from. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 429 | Error | Too many requests. Headers: Retry-After. |
GET /v1/server/stats/games/{gameId}
curl 'https://api.filudi.com/v1/server/stats/games/00000000-0000-0000-0000-000000000000?from=2026-10-30&to=2026-10-30' \ -H "authorization: Bearer $FILUDI_SITE_KEY"// siteKey: an fsk_ key of the site, created in the console; server side onlyconst response = await fetch('https://api.filudi.com/v1/server/stats/games/00000000-0000-0000-0000-000000000000?from=2026-10-30&to=2026-10-30', { headers: { authorization: `Bearer ${siteKey}` },});const data = await response.json();import requests
# site_key: an fsk_ key of the site, created in the consoleresponse = requests.get( 'https://api.filudi.com/v1/server/stats/games/00000000-0000-0000-0000-000000000000?from=2026-10-30&to=2026-10-30', headers={'authorization': f'Bearer {site_key}'},)response.raise_for_status()data = response.json()One game’s numbers on the site for a range of UTC days
Scope stats. Same answer as GET /v1/admin/sites/{siteId}/stats/games/{gameId}. 404 when the game is not on the site catalog.
Credential: a server key (fsk_…), sent as Authorization: Bearer <key> from your backend, never from a browser. Scope stats.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
gameId | path | string (uuid) | yes | |
from | query | string (date) | yes | First UTC day, included |
to | query | string (date) | yes | Last UTC day, included |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
| 200 | GameStats | Game stats. |
| 400 | none | Range over 400 days, or to before from. |
| 401 | Error | No bearer, or a key the API does not know. |
| 403 | Error | The key lacks the scope of this route, is revoked, or its site is not approved; message says which. |
| 404 | Error | Unknown resource. |
| 429 | Error | Too many requests. Headers: Retry-After. |