11 KiB
Backend API
Base URL: http://localhost:8080
All protected endpoints require:
Authorization: Bearer <token>
Access Rules
- Public:
POST /api/auth/loginPOST /api/auth/registerGET /api/invites/validate/:code
- Authorized users:
GET /api/auth/me- read endpoints for games, modules, languages, leaderboards, notifications
admin/moderator:- create/update/delete for games, modules inside games, variables, notifications, leaderboards, groups, languages, invites, image uploads
Auth
Login
POST /api/auth/login
{
"email": "admin@admin.com",
"password": "admin123"
}
Register
POST /api/auth/register
{
"email": "user@example.com",
"username": "player1",
"password": "secret123",
"invite_code": "abcd1234"
}
Current User
GET /api/auth/me
Games
List Games
GET /api/games
Each game includes connected modules.
Example response:
[
{
"id": 5,
"name": "Black & White",
"slug": "b&d",
"description": "Sandbox",
"image_url": "",
"is_active": true,
"modules": [
{
"id": 1,
"key": "variables",
"name": "Variables"
},
{
"id": 2,
"key": "notification",
"name": "Notification"
}
]
}
]
Supports search by game name or slug:
GET /api/games?search=blackGET /api/games?search=b&d
Get Game
GET /api/games/:id
Useful when client is inside a module page and needs the current game slug to restore game search state on exit.
Example response:
{
"id": 5,
"name": "Black & White",
"slug": "b&d",
"description": "Sandbox",
"image_url": "",
"is_active": true,
"modules": [
{
"id": 1,
"key": "variables",
"name": "Variables"
},
{
"id": 2,
"key": "notification",
"name": "Notification"
}
]
}
Create Game
POST /api/games
{
"name": "My Game",
"slug": "my-game",
"description": "Description",
"image_url": ""
}
Update Game
PUT /api/games/:id
Delete Game
DELETE /api/games/:id
Modules
List Available Modules
GET /api/modules
Default modules:
variablesnotificationleaderboard
List Game Modules
GET /api/games/:id/modules
Connect Module To Game
POST /api/games/:id/modules
{
"module_key": "variables"
}
Disconnect Module From Game
DELETE /api/games/:id/modules/:module_key
Languages
Default seeded languages:
en/Englishru/Русский
List Languages
GET /api/languages
Get Language
GET /api/languages/:id
Create Language
POST /api/languages
{
"code": "de",
"name": "Deutsch"
}
Update Language
PUT /api/languages/:id
Delete Language
DELETE /api/languages/:id
User-Game Connections
Search Users In Game
GET /api/games/:id/users?search=...
Returns only users connected to game :id.
Search behavior:
- if
searchis an integer, search by userid - otherwise search by
usernameoremail
Examples:
GET /api/games/5/usersGET /api/games/5/users?search=12GET /api/games/5/users?search=denisGET /api/games/5/users?search=denis@example.com
Example response:
[
{
"id": 12,
"email": "denis@example.com",
"username": "denis",
"role": "user",
"is_active": true,
"created_at": "2026-03-23T20:00:00Z",
"updated_at": "2026-03-23T20:00:00Z"
}
]
List User Games
GET /api/users/:id/games
Connect Game To User
POST /api/users/:id/games
{
"game_id": 5
}
Disconnect Game From User
DELETE /api/users/:id/games/:game_id
Variables
All variable endpoints work only if the game has module variables.
List Variables
GET /api/games/:id/variables
Create Variable
POST /api/games/:id/variables
Number variable:
{
"key": "max_bet",
"type": "number",
"number_value": 100
}
String variable:
{
"key": "welcome_text",
"type": "string",
"string_value": "hello"
}
Table variable with numbers:
{
"key": "rates",
"type": "table",
"table_value_type": "number",
"items": [
{ "key": "bronze", "number_value": 1.1 },
{ "key": "silver", "number_value": 1.3 }
]
}
Table variable with strings:
{
"key": "titles",
"type": "table",
"table_value_type": "string",
"items": [
{ "key": "bronze", "string_value": "Bronze" },
{ "key": "silver", "string_value": "Silver" }
]
}
Vector variable with numbers:
{
"key": "steps",
"type": "vector",
"table_value_type": "number",
"items": [
{ "index": 0, "number_value": 10 },
{ "index": 1, "number_value": 20 }
]
}
Vector variable with strings:
{
"key": "messages",
"type": "vector",
"table_value_type": "string",
"items": [
{ "index": 0, "string_value": "hello" },
{ "index": 1, "string_value": "world" }
]
}
Update Variable
PUT /api/games/:id/variables/:var_id
Delete Variable
DELETE /api/games/:id/variables/:var_id
Variable Rules
type = numberuses onlynumber_valuetype = stringuses onlystring_valuetype = tableuses onlytable_value_typeanditemstype = vectoruses onlytable_value_typeanditems- all table items must use the same value type
- all vector items must use
indexinstead ofkey - vector indexes must be unique and
>= 0 - variable
keyis unique inside one game
Images
Upload Image
POST /api/images
Content type: multipart/form-data
Form field:
file
Example response:
{
"name": "f6e7b0b2-6f8d-4a33-8fc8-2a2f8f6d8c4b.png",
"path": "/uploads/images/f6e7b0b2-6f8d-4a33-8fc8-2a2f8f6d8c4b.png",
"url": "http://localhost:8080/uploads/images/f6e7b0b2-6f8d-4a33-8fc8-2a2f8f6d8c4b.png",
"content_type": "image/png"
}
Static file access:
GET /uploads/images/:filename
Notifications
All notification endpoints work only if the game has module notification.
Notification structure:
- one
notificationhas:name- multilingual
descriptions - shared custom
variables - many
entries
- each
entryhas its own:time_secondimagelogin- values for all shared custom variables
Macros returned by API always include:
{{time_second}}{{image}}{{login}}- all custom variable keys
List Notifications
GET /api/games/:id/notifications
Get Notification
GET /api/games/:id/notifications/:notification_id
Create Notification
POST /api/games/:id/notifications
{
"name": "Welcome bonus",
"descriptions": [
{
"language_id": 1,
"description": "Hello {{login}}, promo {{promo_code}} after {{time_second}} seconds"
},
{
"language_id": 2,
"description": "Привет {{login}}, промокод {{promo_code}} через {{time_second}} секунд"
}
],
"variables": [
{ "key": "promo_code" },
{ "key": "reward" }
],
"entries": [
{
"time_second": 30,
"image": "http://localhost:8080/uploads/images/a.png",
"login": "Denis",
"variables": [
{ "key": "promo_code", "value": "WELCOME30" },
{ "key": "reward", "value": "100" }
]
},
{
"time_second": 60,
"image": "http://localhost:8080/uploads/images/b.png",
"login": "Alex",
"variables": [
{ "key": "promo_code", "value": "WELCOME60" },
{ "key": "reward", "value": "200" }
]
}
]
}
Update Notification
PUT /api/games/:id/notifications/:notification_id
Delete Notification
DELETE /api/games/:id/notifications/:notification_id
Notification Rules
nameis requireddescriptionsmust contain at least one itementriesmust contain at least one item- one
language_idcannot repeat insidedescriptions - top-level
variablesdefine the shared custom variable set - reserved variable keys are forbidden:
time_secondimagelogin
- each entry must contain:
time_second >= 0imagelogin- full set of custom variable values
- entry variable keys must exactly match top-level custom variable keys
Leaderboards
All leaderboard endpoints work only if the game has module leaderboard.
List Game Leaderboards
GET /api/games/:id/leaderboards
Get Leaderboard
GET /api/games/:id/leaderboards/:leaderboard_id
Create Leaderboard
POST /api/games/:id/leaderboards
{
"key": "top_balance",
"name": "Top Balance",
"sort_order": "desc",
"period_type": "all_time",
"is_active": true
}
sort_order:
ascdesc
period_type:
all_timedailyweeklymonthly
Update Leaderboard
PUT /api/games/:id/leaderboards/:leaderboard_id
Delete Leaderboard
DELETE /api/games/:id/leaderboards/:leaderboard_id
List Leaderboard Groups
GET /api/leaderboards/:leaderboard_id/groups
Create Group
POST /api/leaderboards/:leaderboard_id/groups
{
"key": "vip",
"name": "VIP",
"is_default": false
}
Update Group
PUT /api/leaderboard-groups/:group_id
Delete Group
DELETE /api/leaderboard-groups/:group_id
Add Group Member
POST /api/leaderboard-groups/:group_id/members
{
"user_id": 12
}
User must already be connected to the same game.
Delete Group Member
DELETE /api/leaderboard-groups/:group_id/members/:user_id
Save Score
POST /api/leaderboards/:leaderboard_id/scores
{
"user_game_id": 5,
"score": 1200
}
If a score already exists for this user in this leaderboard, it is updated.
Get Rankings
GET /api/leaderboards/:leaderboard_id/rankings
Query params:
group_idoptionallimitoptional, default50, max200
Example:
GET /api/leaderboards/1/rankings?group_id=2&limit=20
Response:
{
"leaderboard": {
"id": 1,
"game_id": 5,
"key": "top_balance",
"name": "Top Balance",
"sort_order": "desc",
"period_type": "all_time",
"is_active": true
},
"items": [
{
"rank": 1,
"user_id": 12,
"user_game_id": 5,
"username": "arnold",
"score": 1200
},
{
"rank": 2,
"user_id": 17,
"user_game_id": 8,
"username": "german",
"score": 950
}
]
}
Leaderboard Rules
- leaderboard
keyis unique inside one game - group
keyis unique inside one leaderboard - score is stored once per
leaderboard_id + user_game_id - groups do not duplicate scores, they only filter ranking members
Balance
Top Up Balance
POST /api/user-games/:ug_id/topup
{
"amount": 100,
"comment": "manual topup"
}
List Transactions
GET /api/user-games/:ug_id/transactions
Invites
Validate Invite
GET /api/invites/validate/:code
Create Invite
POST /api/invites
{
"role": "user",
"max_uses": 10
}
List Invites
GET /api/invites
Delete Invite
DELETE /api/invites/:code
Common Error Patterns
400invalid path param or invalid request body401invalid or missing token403module is not enabled for the target game, or role is insufficient404entity not found409duplicate key / duplicate connection / duplicate membership