{
  "openapi": "3.0.3",
  "info": {
    "title": "AllGame Club API",
    "version": "1.0.0",
    "description": "Players, games, save states, scores and play sessions for AllGame Club. Full docs: https://allgameclub.com/developers",
    "contact": { "email": "developers@allgameclub.com" }
  },
  "servers": [{ "url": "https://allgameclub.com/api/v1" }],
  "components": {
    "securitySchemes": {
      "playerToken": { "type": "http", "scheme": "bearer", "description": "Player token agp_…" },
      "developerKey": { "type": "http", "scheme": "bearer", "description": "Developer key agk_…" }
    },
    "schemas": {
      "Error": { "type": "object", "properties": { "ok": { "type": "boolean", "example": false }, "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } } } } },
      "Entitlement": { "type": "object", "properties": { "unlimited": { "type": "boolean" }, "allowance_seconds": { "type": "integer" }, "used_seconds": { "type": "integer" }, "remaining_seconds": { "type": "integer", "nullable": true }, "limit_reached": { "type": "boolean" }, "resets_in_seconds": { "type": "integer" }, "day": { "type": "string" } } },
      "Player": { "type": "object", "properties": { "id": { "type": "integer" }, "username": { "type": "string" }, "display_name": { "type": "string" }, "avatar_url": { "type": "string" }, "bio": { "type": "string", "nullable": true }, "country": { "type": "string", "nullable": true }, "member_since": { "type": "string" } } },
      "Game": { "type": "object", "properties": { "slug": { "type": "string" }, "name": { "type": "string" }, "tagline": { "type": "string", "nullable": true }, "description": { "type": "string", "nullable": true }, "category": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "version": { "type": "string" }, "leaderboard": { "type": "object" }, "save_slots": { "type": "integer" }, "requires_premium": { "type": "boolean" }, "status": { "type": "string" }, "cover_url": { "type": "string" }, "play_url": { "type": "string" } } },
      "State": { "type": "object", "properties": { "slot": { "type": "integer" }, "label": { "type": "string", "nullable": true }, "version": { "type": "integer" }, "size_bytes": { "type": "integer" }, "state": {}, "updated_at": { "type": "string" } } },
      "LeaderboardRow": { "type": "object", "properties": { "rank": { "type": "integer" }, "score": { "type": "integer" }, "entries": { "type": "integer" }, "last_played": { "type": "string" }, "player": { "$ref": "#/components/schemas/Player" } } }
    },
    "responses": { "Error": { "description": "Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }
  },
  "paths": {
    "/status": { "get": { "summary": "Health check", "responses": { "200": { "description": "OK" } } } },
    "/auth/register": { "post": { "summary": "Register a player", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["email", "password", "display_name"], "properties": { "email": { "type": "string" }, "password": { "type": "string", "minLength": 8 }, "display_name": { "type": "string" }, "username": { "type": "string" }, "newsletter": { "type": "boolean" } } } } } }, "responses": { "201": { "description": "Player and token" }, "409": { "$ref": "#/components/responses/Error" }, "422": { "$ref": "#/components/responses/Error" } } } },
    "/auth/login": { "post": { "summary": "Log in and receive a player token", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["login", "password"], "properties": { "login": { "type": "string" }, "password": { "type": "string" }, "device_name": { "type": "string" } } } } } }, "responses": { "200": { "description": "Token" }, "401": { "$ref": "#/components/responses/Error" } } } },
    "/auth/logout": { "post": { "summary": "Revoke the current token", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "OK" } } } },
    "/auth/forgot-password": { "post": { "summary": "Send a password reset email", "responses": { "200": { "description": "Always OK" } } } },
    "/me": {
      "get": { "summary": "Current player", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "Player, entitlement, membership" } } },
      "patch": { "summary": "Update profile", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "Updated player" }, "409": { "$ref": "#/components/responses/Error" } } }
    },
    "/me/avatar": {
      "post": { "summary": "Upload avatar (multipart field avatar)", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "avatar_url" } } },
      "delete": { "summary": "Remove avatar", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "avatar_url" } } }
    },
    "/me/entitlement": { "get": { "summary": "Today's play allowance", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "Entitlement", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Entitlement" } } } } } } },
    "/me/playtime": { "get": { "summary": "Play time history", "security": [{ "playerToken": [] }], "parameters": [{ "name": "days", "in": "query", "schema": { "type": "integer", "default": 14 } }], "responses": { "200": { "description": "History" } } } },
    "/me/scores": { "get": { "summary": "Best and recent scores", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "Scores" } } } },
    "/me/tokens": {
      "get": { "summary": "List tokens", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "Tokens" } } },
      "post": { "summary": "Create token", "security": [{ "playerToken": [] }], "responses": { "201": { "description": "Token" } } }
    },
    "/me/tokens/{id}": { "delete": { "summary": "Revoke token", "security": [{ "playerToken": [] }], "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } } },
    "/players/{username}": { "get": { "summary": "Public profile", "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Profile" }, "404": { "$ref": "#/components/responses/Error" } } } },
    "/games": { "get": { "summary": "List games", "parameters": [{ "name": "category", "in": "query", "schema": { "type": "string" } }, { "name": "q", "in": "query", "schema": { "type": "string" } }], "responses": { "200": { "description": "Games", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "object", "properties": { "games": { "type": "array", "items": { "$ref": "#/components/schemas/Game" } } } } } } } } } } } },
    "/games/{slug}": { "get": { "summary": "Game details", "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Game" }, "404": { "$ref": "#/components/responses/Error" } } } },
    "/games/{slug}/favorite": { "post": { "summary": "Toggle favorite", "security": [{ "playerToken": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "is_favorite" } } } },
    "/games/{slug}/leaderboard": { "get": { "summary": "Leaderboard", "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "board", "in": "query", "schema": { "type": "string", "default": "main" } }, { "name": "period", "in": "query", "schema": { "type": "string", "enum": ["all", "month", "week", "day"] } }, { "name": "limit", "in": "query", "schema": { "type": "integer", "maximum": 100 } }, { "name": "offset", "in": "query", "schema": { "type": "integer" } }], "responses": { "200": { "description": "Rows", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "object", "properties": { "leaderboard": { "type": "array", "items": { "$ref": "#/components/schemas/LeaderboardRow" } } } } } } } } } } } },
    "/games/{slug}/leaderboard/me": { "get": { "summary": "My rank", "security": [{ "playerToken": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Rank" } } } },
    "/games/{slug}/scores": { "post": { "summary": "Submit a score", "security": [{ "playerToken": [] }, { "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["score"], "properties": { "score": { "type": "integer" }, "board": { "type": "string" }, "meta": { "type": "object" }, "play_session": { "type": "string" }, "player_id": { "type": "integer" } } } } } }, "responses": { "201": { "description": "Accepted" } } } },
    "/games/{slug}/scores/me": { "get": { "summary": "My scores for a game", "security": [{ "playerToken": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Scores" } } } },
    "/games/{slug}/states": { "get": { "summary": "List save slots", "security": [{ "playerToken": [] }, { "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "player_id", "in": "query", "schema": { "type": "integer" } }], "responses": { "200": { "description": "Slots" } } } },
    "/games/{slug}/states/{slot}": {
      "get": { "summary": "Read a save state", "security": [{ "playerToken": [] }, { "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "slot", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "State", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/State" } } } }, "404": { "$ref": "#/components/responses/Error" } } },
      "put": { "summary": "Save a state", "security": [{ "playerToken": [] }, { "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "slot", "in": "path", "required": true, "schema": { "type": "integer" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["state"], "properties": { "state": {}, "label": { "type": "string" }, "expected_version": { "type": "integer" }, "player_id": { "type": "integer" } } } } } }, "responses": { "200": { "description": "Updated" }, "201": { "description": "Created" }, "409": { "$ref": "#/components/responses/Error" }, "413": { "$ref": "#/components/responses/Error" } } },
      "delete": { "summary": "Delete a save state", "security": [{ "playerToken": [] }, { "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "slot", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "deleted" } } }
    },
    "/play/start": { "post": { "summary": "Start a play session", "security": [{ "playerToken": [] }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["game"], "properties": { "game": { "type": "string" } } } } } }, "responses": { "200": { "description": "Session and entitlement" }, "402": { "$ref": "#/components/responses/Error" } } } },
    "/play/heartbeat": { "post": { "summary": "Heartbeat (credits play time)", "security": [{ "playerToken": [] }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["session"], "properties": { "session": { "type": "string" } } } } } }, "responses": { "200": { "description": "Entitlement" }, "410": { "$ref": "#/components/responses/Error" } } } },
    "/play/end": { "post": { "summary": "End a play session", "security": [{ "playerToken": [] }], "responses": { "200": { "description": "Session summary" } } } },
    "/dev/players/{id}": { "get": { "summary": "Public profile by id", "security": [{ "developerKey": [] }], "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "Profile" } } } },
    "/dev/players/{id}/entitlement": { "get": { "summary": "Player entitlement", "security": [{ "developerKey": [] }], "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "Entitlement" } } } },
    "/dev/games/{slug}/players/{id}/states": { "get": { "summary": "Player's states for a game", "security": [{ "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }, { "name": "include_state", "in": "query", "schema": { "type": "boolean" } }], "responses": { "200": { "description": "States" } } } },
    "/dev/games/{slug}/players/{id}/states/{slot}": { "put": { "summary": "Save a player's state", "security": [{ "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }, { "name": "slot", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "Saved" } } } },
    "/dev/games/{slug}/players/{id}/scores": { "post": { "summary": "Submit a score for a player", "security": [{ "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "201": { "description": "Accepted" } } } },
    "/dev/games/{slug}/stats": { "get": { "summary": "Game statistics", "security": [{ "developerKey": [] }], "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Stats" } } } }
  }
}
