Skip to content

MAID Admin API Reference

The MAID Admin API provides a comprehensive REST/WebSocket interface for server administration, monitoring, and management. All endpoints are prefixed with /admin.

Admin Web UI

MAID includes a React-based admin web interface that provides a visual dashboard for server management.

Building the Admin UI

The admin frontend is located at packages/maid-engine/admin_frontend/. To build it:

# Navigate to the admin frontend directory
cd packages/maid-engine/admin_frontend

# Install dependencies
npm install

# Build for production
npm run build

# For development with hot reload (connects to API on localhost:8080)
npm run dev

Accessing the Admin UI

Once built, the admin UI is automatically served by the MAID server:

  • Production: http://your-server:8080/admin-ui/
  • Development: http://localhost:3000/ (with Vite dev server)

The production build is served from packages/maid-engine/admin_frontend/dist/ via FastAPI's StaticFiles mount.

UI Features

  • Dashboard: Real-time server metrics and performance graphs
  • Players: View and manage online players, ban/kick functionality
  • Entities: Browse and edit game entities and their components
  • World: View room topology and navigate the game world
  • Logs: Search and stream server logs in real-time
  • Config: View and modify server configuration

Table of Contents


Authentication

The Admin API uses JWT (JSON Web Tokens) for authentication. Tokens are issued upon login and must be included in the Authorization header of subsequent requests.

Login

POST /admin/auth/login

Authenticate with username and password to receive access and refresh tokens.

Request Body:

{
  "username": "admin",
  "password": "secret"
}

Response (200):

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "username": "admin",
    "role": "ADMIN",
    "permissions": ["view", "edit", "admin"]
  }
}

Errors: - 401 - Invalid credentials - 403 - Account locked or disabled

Refresh Token

POST /admin/auth/refresh

Exchange a refresh token for a new access token.

Request Body:

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response (200):

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600
}

Logout

POST /admin/auth/logout

Revoke the current access token.

Headers:

Authorization: Bearer <access_token>

Response (200):

{
  "message": "Successfully logged out"
}

Get Current User

GET /admin/auth/me

Get information about the currently authenticated user.

Response (200):

{
  "username": "admin",
  "role": "ADMIN",
  "permissions": ["view", "edit", "admin"],
  "last_login": "2024-01-15T10:30:00Z"
}

Admin Roles

Role Description Capabilities
VIEWER Read-only access View entities, logs, metrics
BUILDER World building Create/modify rooms, entities
ADMIN Administration Manage players, reload packs
SUPERADMIN Full access All operations including config

Dashboard

Real-time server metrics and monitoring.

Get All Metrics

GET /admin/dashboard/

Get comprehensive dashboard metrics.

Response (200):

{
  "server": {
    "uptime_seconds": 86400,
    "tick_rate": 4.0,
    "current_tick": 345600,
    "memory_mb": 256.5,
    "cpu_percent": 12.3
  },
  "players": {
    "online_count": 42,
    "total_accounts": 1234,
    "active_sessions": 42,
    "peak_today": 67
  },
  "world": {
    "room_count": 500,
    "entity_count": 2345,
    "loaded_areas": 12,
    "active_npcs": 189
  },
  "performance": {
    "avg_tick_ms": 2.5,
    "max_tick_ms": 15.3,
    "commands_per_second": 8.7
  }
}

Get Server Metrics

GET /admin/dashboard/server

Get server-specific metrics including CPU, memory, and tick performance.

Get Player Metrics

GET /admin/dashboard/players

Get player statistics and session information.

Get World Metrics

GET /admin/dashboard/world

Get world state metrics including entity counts and area information.


Entity Management

CRUD operations for game entities.

List Entities

GET /admin/entities/

List entities with filtering and pagination.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | page | int | Page number (1-indexed) | | page_size | int | Items per page (1-100) | | type | string | Filter by entity type | | room_id | UUID | Filter by room | | has_tag | string | Filter by tag | | search | string | Search by name |

Response (200):

{
  "entities": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Sword of Destiny",
      "type": "item",
      "room_id": "660e8400-e29b-41d4-a716-446655440001",
      "tags": ["weapon", "magic"],
      "component_types": ["ItemComponent", "DamageComponent"]
    }
  ],
  "total": 100,
  "page": 1,
  "page_size": 20,
  "has_next": true
}

Get Entity

GET /admin/entities/{entity_id}

Get detailed information about a specific entity.

Response (200):

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Sword of Destiny",
  "type": "item",
  "room_id": "660e8400-e29b-41d4-a716-446655440001",
  "tags": ["weapon", "magic"],
  "components": {
    "ItemComponent": {
      "weight": 5.0,
      "value": 1000
    },
    "DamageComponent": {
      "damage_type": "slashing",
      "damage_dice": "2d6+3"
    }
  },
  "metadata": {
    "created_at": "2024-01-15T10:30:00Z",
    "created_by": "admin"
  }
}

Create Entity

POST /admin/entities/

Create a new entity.

Required Role: BUILDER

Request Body:

{
  "name": "Iron Sword",
  "type": "item",
  "room_id": "660e8400-e29b-41d4-a716-446655440001",
  "tags": ["weapon"],
  "components": {
    "ItemComponent": {
      "weight": 3.0,
      "value": 50
    }
  }
}

Response (201):

{
  "id": "770e8400-e29b-41d4-a716-446655440002",
  "name": "Iron Sword",
  "message": "Entity created successfully"
}

Delete Entity

DELETE /admin/entities/{entity_id}

Delete an entity from the world.

Required Role: ADMIN

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | force | bool | Force deletion even if entity has dependents |

Response (200):

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "message": "Entity deleted successfully"
}

Update Component

PUT /admin/entities/{entity_id}/components/{component_type}

Update a component on an entity.

Required Role: BUILDER

Request Body:

{
  "damage_dice": "3d6+5"
}

Add Component

POST /admin/entities/{entity_id}/components

Add a new component to an entity.

Required Role: BUILDER

Request Body:

{
  "type": "HealthComponent",
  "data": {
    "max_hp": 100,
    "current_hp": 100
  }
}

Remove Component

DELETE /admin/entities/{entity_id}/components/{component_type}

Remove a component from an entity.

Required Role: BUILDER

Add Tag

POST /admin/entities/{entity_id}/tags/{tag}

Add a tag to an entity.

Required Role: BUILDER

Remove Tag

DELETE /admin/entities/{entity_id}/tags/{tag}

Remove a tag from an entity.

Required Role: BUILDER


Player Management

Manage player accounts and sessions.

List Players

GET /admin/players/

List player accounts with filtering.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | page | int | Page number | | page_size | int | Items per page | | online_only | bool | Only show online players | | search | string | Search by username | | banned | bool | Filter by ban status |

Response (200):

{
  "players": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "username": "player1",
      "email": "player1@example.com",
      "is_online": true,
      "is_banned": false,
      "access_level": "PLAYER",
      "created_at": "2024-01-01T00:00:00Z",
      "last_login": "2024-01-15T10:30:00Z"
    }
  ],
  "total": 1234,
  "page": 1,
  "page_size": 20
}

Get Player Details

GET /admin/players/{player_id}

Get detailed information about a player.

Response (200):

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "player1",
  "email": "player1@example.com",
  "is_online": true,
  "is_banned": false,
  "access_level": "PLAYER",
  "created_at": "2024-01-01T00:00:00Z",
  "last_login": "2024-01-15T10:30:00Z",
  "play_time_hours": 156.5,
  "character_count": 3,
  "current_character_id": "660e8400-e29b-41d4-a716-446655440001",
  "ip_address": "192.168.1.100",
  "session_start": "2024-01-15T10:00:00Z"
}

Get Player Characters

GET /admin/players/{player_id}/characters

List all characters belonging to a player.

Ban Player

POST /admin/players/{player_id}/ban

Ban a player account.

Required Role: ADMIN

Request Body:

{
  "reason": "Violation of terms of service",
  "duration_hours": 24,
  "notify": true
}

Unban Player

POST /admin/players/{player_id}/unban

Remove a ban from a player account.

Required Role: ADMIN

Kick Player

POST /admin/players/{player_id}/kick

Disconnect a player's current session.

Required Role: ADMIN

Request Body:

{
  "reason": "Server maintenance",
  "message": "The server will restart in 5 minutes."
}

Set Access Level

PUT /admin/players/{player_id}/access-level

Change a player's access level.

Required Role: SUPERADMIN

Request Body:

{
  "access_level": "BUILDER"
}

Send Message

POST /admin/players/{player_id}/message

Send a message to a player.

Required Role: ADMIN

Request Body:

{
  "message": "Welcome to MAID!",
  "type": "system"
}


World Management

Manage rooms, exits, and areas.

List Rooms

GET /admin/world/rooms

List rooms with filtering and pagination.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | page | int | Page number (1-indexed) | | page_size | int | Items per page (1-100) | | area_id | UUID | Filter by area | | search | string | Search by room name |

Response (200):

{
  "rooms": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Town Square",
      "description": "The central square of the town.",
      "area_id": "660e8400-e29b-41d4-a716-446655440001",
      "area_name": "Town",
      "exits": [
        {
          "direction": "north",
          "destination_id": "770e8400-e29b-41d4-a716-446655440002",
          "destination_name": "Market Street",
          "is_locked": false
        }
      ],
      "entity_count": 5,
      "player_count": 2
    }
  ],
  "total": 500,
  "page": 1,
  "page_size": 50,
  "has_next": true,
  "has_previous": false
}

Get Room

GET /admin/world/rooms/{room_id}

Get detailed information about a room.

Create Room

POST /admin/world/rooms

Create a new room.

Required Role: BUILDER

Request Body:

{
  "name": "Secret Chamber",
  "description": "A hidden chamber behind the waterfall.",
  "area_id": "660e8400-e29b-41d4-a716-446655440001",
  "metadata": {
    "hidden": true,
    "terrain": "cave"
  }
}

Response (201):

{
  "id": "880e8400-e29b-41d4-a716-446655440003",
  "name": "Secret Chamber",
  "message": "Room created successfully"
}

Update Room

PUT /admin/world/rooms/{room_id}

Update a room's properties.

Required Role: BUILDER

Request Body:

{
  "name": "Updated Room Name",
  "description": "New description",
  "metadata": {
    "terrain": "stone"
  }
}

Delete Room

DELETE /admin/world/rooms/{room_id}

Delete a room and all its exits.

Required Role: ADMIN

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | force | bool | Force deletion even if room contains entities |

Create Exit

POST /admin/world/exits

Create an exit between two rooms.

Required Role: BUILDER

Request Body:

{
  "from_room_id": "550e8400-e29b-41d4-a716-446655440000",
  "to_room_id": "660e8400-e29b-41d4-a716-446655440001",
  "direction": "north",
  "bidirectional": true,
  "reverse_direction": "south",
  "is_locked": false
}

Response (201):

{
  "from_room_id": "550e8400-e29b-41d4-a716-446655440000",
  "to_room_id": "660e8400-e29b-41d4-a716-446655440001",
  "direction": "north",
  "reverse_created": true,
  "message": "Exit created successfully"
}

Delete Exit

DELETE /admin/world/exits/{room_id}/{direction}

Delete an exit from a room.

Required Role: BUILDER

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | bidirectional | bool | Also delete the reverse exit |

Get World Graph

GET /admin/world/graph

Get the world topology as a graph for visualization.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | area_id | UUID | Filter to a specific area |

Response (200):

{
  "nodes": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "label": "Town Square",
      "area_id": "660e8400-e29b-41d4-a716-446655440001",
      "area_name": "Town",
      "player_count": 2
    }
  ],
  "edges": [
    {
      "source": "550e8400-e29b-41d4-a716-446655440000",
      "target": "770e8400-e29b-41d4-a716-446655440002",
      "label": "north",
      "bidirectional": true
    }
  ],
  "total_rooms": 500,
  "total_exits": 1200,
  "total_areas": 12
}

List Areas

GET /admin/world/areas

List all areas/zones in the world.

Response (200):

{
  "areas": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Town",
      "description": "The main town area",
      "room_count": 50,
      "player_count": 15,
      "metadata": {}
    }
  ],
  "total": 12
}


Logs

View, search, and export server logs.

Search Logs

GET /admin/logs/

Search log entries with filters.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | start_time | datetime | Start of time range | | end_time | datetime | End of time range | | level | string | Minimum log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) | | logger_name | string | Logger name prefix | | message_pattern | string | Regex pattern for message | | limit | int | Maximum results (1-1000) | | offset | int | Pagination offset |

Response (200):

{
  "entries": [
    {
      "timestamp": "2024-01-15T10:30:00Z",
      "level": "INFO",
      "logger_name": "maid_engine.core.engine",
      "message": "Server started successfully",
      "module": "engine",
      "func_name": "start",
      "line_no": 123,
      "exc_info": null
    }
  ],
  "total": 1500,
  "has_more": true
}

Get Recent Logs

GET /admin/logs/recent

Get the most recent log entries.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | count | int | Number of entries (1-500) |

List Loggers

GET /admin/logs/loggers

Get information about all known loggers.

Response (200):

[
  {
    "name": "maid_engine.core.engine",
    "level": "INFO",
    "effective_level": "INFO",
    "handlers_count": 2
  }
]

Export Logs

POST /admin/logs/export

Export logs to JSON or CSV format.

Required Role: ADMIN

Request Body:

{
  "format": "json",
  "start_time": "2024-01-15T00:00:00Z",
  "end_time": "2024-01-15T23:59:59Z",
  "level": "WARNING",
  "max_entries": 10000
}

Response: Streaming file download

Get Log Statistics

GET /admin/logs/stats

Get statistics about logged messages.

Response (200):

{
  "total_entries": 10000,
  "buffer_capacity": 10000,
  "by_level": {
    "DEBUG": 5000,
    "INFO": 3500,
    "WARNING": 1000,
    "ERROR": 450,
    "CRITICAL": 50
  },
  "top_loggers": {
    "maid_engine.core.engine": 2500,
    "maid_engine.network.telnet": 1500
  }
}


Configuration

View and modify server configuration.

Get All Configuration

GET /admin/config/

Get all configuration sections.

Response (200):

[
  {
    "name": "game",
    "description": "Core game engine settings",
    "fields": {
      "tick_rate": 4.0,
      "max_players": 1000
    },
    "schema_info": {
      "tick_rate": {
        "type": "float",
        "description": "Game ticks per second",
        "is_secret": false,
        "required": false,
        "default": 4.0
      }
    }
  }
]

Get Configuration Section

GET /admin/config/{section}

Get a specific configuration section.

Get Configuration Value

GET /admin/config/{section}/{key}

Get a specific configuration value.

Response (200):

{
  "section": "game",
  "key": "tick_rate",
  "value": 4.0,
  "value_type": "float",
  "description": "Game ticks per second",
  "is_secret": false,
  "is_mutable": true
}

Validate Configuration Change

POST /admin/config/validate

Validate a proposed configuration change without applying it.

Required Role: ADMIN

Request Body:

{
  "section": "game",
  "key": "tick_rate",
  "value": 8.0
}

Response (200):

{
  "valid": true,
  "errors": [],
  "warnings": [],
  "current_value": 4.0
}

Update Configuration Value

PUT /admin/config/{section}/{key}

Update a configuration value at runtime.

Required Role: SUPERADMIN

Request Body:

{
  "value": 8.0
}

Reload Configuration

POST /admin/config/reload

Reload configuration from files and clear runtime overrides.

Required Role: SUPERADMIN

Get Runtime Overrides

GET /admin/config/overrides

Get all runtime configuration overrides.

Required Role: ADMIN

Clear Runtime Override

DELETE /admin/config/{section}/{key}/override

Clear a runtime override and revert to the base value.

Required Role: SUPERADMIN


Content Packs

Manage content packs (plugins).

List Content Packs

GET /admin/packs/

List all available and loaded content packs.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | loaded_only | bool | Only show loaded packs |

Response (200):

{
  "packs": [
    {
      "name": "maid-stdlib",
      "display_name": "MAID Standard Library",
      "version": "0.1.0",
      "description": "Standard components and utilities",
      "is_loaded": true,
      "is_available": true
    }
  ],
  "total_available": 5,
  "total_loaded": 3
}

Get Pack Details

GET /admin/packs/{pack_name}

Get detailed information about a content pack.

Response (200):

{
  "manifest": {
    "name": "maid-stdlib",
    "version": "0.1.0",
    "display_name": "MAID Standard Library",
    "description": "Standard components and utilities",
    "authors": ["MAID Team"],
    "license": "MIT",
    "homepage": "https://github.com/example/maid",
    "keywords": ["stdlib", "components"]
  },
  "status": {
    "is_loaded": true,
    "is_available": true,
    "can_unload": false,
    "blocking_dependents": ["maid-classic-rpg"],
    "load_order": 0
  },
  "dependencies": [],
  "capabilities": {
    "provides": ["stdlib"],
    "requires": []
  },
  "resources": {
    "systems": 5,
    "events": 12,
    "commands": 15
  }
}

Reload Content Pack

POST /admin/packs/{pack_name}/reload

Reload a content pack (unload and load again).

Required Role: ADMIN

Response (200):

{
  "success": true,
  "message": "Content pack 'maid-stdlib' reloaded successfully",
  "pack_name": "maid-stdlib",
  "reload_time_ms": 125.5
}

Get Pack Dependencies

GET /admin/packs/{pack_name}/dependencies

Get the dependency tree for a content pack.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | include_transitive | bool | Include indirect dependencies |

Get Pack Dependents

GET /admin/packs/{pack_name}/dependents

Get packs that depend on this pack.

Get Load Order

GET /admin/packs/load-order

Get the order in which packs were loaded.


WebSocket Endpoints

Main Admin WebSocket

WS /admin/ws

Main WebSocket connection for subscribing to various channels.

Authentication: Include JWT token as query parameter or in first message.

Subscribe to channels:

{
  "type": "subscribe",
  "channels": ["players", "world", "logs"]
}

Receive updates:

{
  "type": "player_connected",
  "data": {
    "player_id": "550e8400-e29b-41d4-a716-446655440000",
    "username": "player1"
  }
}

Dashboard WebSocket

WS /admin/dashboard/ws

Real-time dashboard metrics streaming.

Receive metrics:

{
  "type": "metrics_update",
  "data": {
    "timestamp": "2024-01-15T10:30:00Z",
    "tick_ms": 2.5,
    "players_online": 42,
    "memory_mb": 256.5
  }
}

Log Stream WebSocket

WS /admin/logs/stream

Real-time log streaming via WebSocket.

Connection confirmation:

{
  "type": "connected",
  "message": "Connected to log stream"
}

Receive log entries:

{
  "type": "log_entry",
  "data": {
    "timestamp": "2024-01-15T10:30:00Z",
    "level": "INFO",
    "logger_name": "maid_engine.core.engine",
    "message": "Player connected: player1"
  }
}

Send ping:

{
  "type": "ping"
}

Receive pong:

{
  "type": "pong"
}


Error Responses

All endpoints return standard HTTP error codes with JSON error bodies:

{
  "detail": "Error message describing what went wrong"
}
Code Description
400 Bad Request - Invalid input
401 Unauthorized - Invalid or missing token
403 Forbidden - Insufficient permissions
404 Not Found - Resource does not exist
409 Conflict - Resource already exists
500 Internal Server Error
503 Service Unavailable - Engine not ready

Rate Limiting

The Admin API may implement rate limiting. When rate limited, you will receive:

  • Status code: 429 Too Many Requests
  • Headers:
  • X-RateLimit-Limit: Maximum requests per window
  • X-RateLimit-Remaining: Requests remaining
  • X-RateLimit-Reset: Timestamp when limit resets