Skip to content

REST API Documentation

This guide covers the MAID v1 REST API for external integrations, including authentication, rate limiting, endpoints, and real-time event streaming.

Overview

The MAID REST API provides programmatic access to server data and administrative functions. It is designed for: - External tools and dashboards - Discord/IRC bots - Monitoring systems - Custom integrations

Base URL: /api/v1

OpenAPI Documentation: - Swagger UI: /api/docs - ReDoc: /api/redoc - OpenAPI JSON: /api/openapi.json

Note: OpenAPI documentation is automatically generated by FastAPI based on the endpoint definitions, Pydantic models, and docstrings in the codebase. No separate OpenAPI specification file is maintained.


Authentication

The API uses API key authentication via the X-API-Key header.

Obtaining an API Key

API keys are generated through the CLI or admin API:

# Generate a new API key
uv run maid api generate-key --name "My Integration" --permissions READ_PUBLIC,READ_PLAYERS

# Output:
# API Key created successfully!
# Key ID: 550e8400-e29b-41d4-a716-446655440000
# Name: My Integration
# Permissions: READ_PUBLIC, READ_PLAYERS
#
# IMPORTANT: Save this key now - it cannot be retrieved later!
# API Key: maid_550e8400_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Using the API Key

Include the key in the X-API-Key header:

curl -X GET "http://localhost:8080/api/v1/players" \
  -H "X-API-Key: maid_550e8400_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

API Key Format

Keys follow the format: maid_{key_id_prefix}_{secret}

  • maid_ - Prefix for identification
  • {key_id_prefix} - First 8 characters of the key UUID
  • {secret} - 32-character secure random token

Permissions

Permission Description
READ_PUBLIC Read public server information
READ_PLAYERS Read player data
WRITE_PLAYERS Modify player data
READ_WORLD Read world data (rooms, NPCs, items)
WRITE_WORLD Modify world data
ADMIN Administrative actions

Permission Combinations: - READ_ALL = READ_PUBLIC + READ_PLAYERS + READ_WORLD - WRITE_ALL = WRITE_PLAYERS + WRITE_WORLD - FULL_ACCESS = All permissions


Rate Limiting

The API implements sliding window rate limiting.

Default Limits

  • Per API Key: 60 requests/minute (configurable per key)
  • Sliding window: 60 seconds

Rate Limit Headers

All responses include rate limit information:

Header Description
X-RateLimit-Limit Maximum requests per window
X-RateLimit-Remaining Remaining requests in window
X-RateLimit-Reset Unix timestamp when limit resets

Rate Limit Exceeded

When rate limited, the API returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Remaining: 0

{
  "detail": "Rate limit exceeded"
}

Endpoints

Health Check

GET /api/v1/health

Check API health status. No authentication required.

Response:

{
  "status": "ok",
  "timestamp": "2024-01-15T10:30:00Z",
  "version": "0.1.0",
  "uptime_seconds": 86400
}

Example:

curl http://localhost:8080/api/v1/health

Players API

List Players

GET /api/v1/players

List players with pagination, filtering, and sorting.

Required Permission: READ_PLAYERS

Query Parameters:

Parameter Type Default Description
page int 1 Page number (1-indexed)
page_size int 50 Items per page (1-100)
search str None Search by username or email
status str None Filter by status (active, banned, suspended)
role str None Filter by role
online_only bool false Only show online players
sort_by str username Sort field (username, created_at, last_login, status)
sort_order str asc Sort order (asc, desc)

Response:

{
  "players": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "username": "player1",
      "status": "active",
      "role": "user",
      "is_online": true,
      "created_at": "2024-01-15T10:30:00Z",
      "last_login": "2024-01-20T15:45:00Z"
    }
  ],
  "total": 150,
  "page": 1,
  "page_size": 50,
  "has_next": true,
  "has_previous": false
}

Example:

curl "http://localhost:8080/api/v1/players?online_only=true&page_size=10" \
  -H "X-API-Key: maid_xxx..."

Get Player Details

GET /api/v1/players/{player_id}

Get detailed information about a specific player.

Required Permission: READ_PLAYERS

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "player1",
  "email": "player@example.com",
  "status": "active",
  "role": "user",
  "is_online": true,
  "created_at": "2024-01-15T10:30:00Z",
  "last_login": "2024-01-20T15:45:00Z",
  "login_attempts": 0,
  "locked_until": null,
  "current_character": "char-123",
  "current_location": "Town Square",
  "metadata": {}
}

Update Player

PATCH /api/v1/players/{player_id}

Update player account data.

Required Permission: WRITE_PLAYERS

Request Body:

{
  "email": "newemail@example.com",
  "metadata": {"notes": "VIP player"}
}

Response:

{
  "player_id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "player1",
  "updated_fields": ["email", "metadata"],
  "success": true,
  "message": "Updated 2 field(s)"
}

Kick Player

POST /api/v1/players/{player_id}/kick

Disconnect an active player session.

Required Permission: ADMIN

Request Body:

{
  "reason": "Server maintenance"
}

Response:

{
  "player_id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "player1",
  "reason": "Server maintenance",
  "success": true,
  "message": "Player kicked successfully"
}

Ban Player

POST /api/v1/players/{player_id}/ban

Ban a player account.

Required Permission: ADMIN

Request Body:

{
  "reason": "Violation of community guidelines",
  "duration_hours": 24
}

Response:

{
  "player_id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "player1",
  "reason": "Violation of community guidelines",
  "banned_until": "2024-01-16T10:30:00Z",
  "success": true,
  "message": "Player banned successfully"
}

Unban Player

DELETE /api/v1/players/{player_id}/ban

Remove a ban from a player account.

Required Permission: ADMIN

Response:

{
  "player_id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "player1",
  "success": true,
  "message": "Player unbanned successfully"
}

World API

List Rooms

GET /api/v1/world/rooms

List all rooms with optional filtering.

Required Permission: READ_WORLD

Query Parameters:

Parameter Type Default Description
area_id str None Filter by area ID
offset int 0 Pagination offset
limit int 50 Items per page (1-100)

Response:

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Town Square",
      "area_id": "660e8400-e29b-41d4-a716-446655440001",
      "area_name": "Town",
      "entity_count": 5
    }
  ],
  "total": 500,
  "offset": 0,
  "limit": 50,
  "has_more": true
}

Get Room Details

GET /api/v1/world/rooms/{room_id}

Get detailed information about a specific room.

Required Permission: READ_WORLD

Response:

{
  "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,
  "properties": {
    "terrain": "cobblestone",
    "light_level": "bright"
  }
}

Get Room Contents

GET /api/v1/world/rooms/{room_id}/contents

Get the contents of a room (players, NPCs, items).

Required Permission: READ_WORLD

Response:

{
  "room_id": "550e8400-e29b-41d4-a716-446655440000",
  "room_name": "Town Square",
  "players": [
    {"id": "aaa...", "name": "Player1", "entity_type": "player", "description": ""}
  ],
  "npcs": [
    {"id": "bbb...", "name": "Guard", "entity_type": "npc", "description": "A town guard"}
  ],
  "items": [
    {"id": "ccc...", "name": "Sword", "entity_type": "item", "description": "A rusty sword"}
  ],
  "total_count": 3
}

List NPCs

GET /api/v1/world/npcs

List all NPCs with optional filtering.

Required Permission: READ_WORLD

Query Parameters:

Parameter Type Description
room_id str Filter by room ID
npc_type str Filter by NPC type
is_hostile bool Filter by hostility
offset int Pagination offset
limit int Items per page

List Items

GET /api/v1/world/items

List all items (on ground) with optional filtering.

Required Permission: READ_WORLD

Query Parameters:

Parameter Type Description
room_id str Filter by room ID
item_type str Filter by item type
is_takeable bool Filter by takeability
offset int Pagination offset
limit int Items per page

List Areas

GET /api/v1/world/areas

List all areas/zones.

Required Permission: READ_WORLD


Statistics API

Server Statistics

GET /api/v1/stats/server

Get server statistics. No authentication required.

Response:

{
  "uptime_seconds": 86400,
  "tick_rate": 4.0,
  "current_tick": 345600,
  "connected_players": 42,
  "memory_usage_mb": 256.5,
  "cpu_usage_percent": null,
  "version": "0.1.0",
  "start_time": "2024-01-14T10:30:00Z"
}

Player Statistics

GET /api/v1/stats/players

Get player statistics. No authentication required.

Response:

{
  "online_count": 42,
  "peak_players_today": 67,
  "peak_players_all_time": 150,
  "new_registrations_today": 5,
  "new_registrations_this_week": 28,
  "total_accounts": 1234,
  "active_sessions": 42
}

Economy Statistics

GET /api/v1/stats/economy

Get economy statistics. No authentication required.

Response:

{
  "total_currency_in_circulation": 1500000,
  "transactions_today": 342,
  "transactions_this_week": 2156,
  "average_player_wealth": 1216.5,
  "median_player_wealth": 500,
  "top_player_wealth": 50000,
  "currency_name": "gold"
}

Combat Statistics

GET /api/v1/stats/combat

Get combat statistics. No authentication required.

Response:

{
  "battles_today": 156,
  "battles_this_week": 1089,
  "player_deaths_today": 23,
  "player_deaths_this_week": 178,
  "mob_kills_today": 412,
  "mob_kills_this_week": 2891,
  "total_damage_dealt_today": 145678,
  "total_damage_dealt_this_week": 1023456,
  "pvp_battles_today": 12,
  "pvp_battles_this_week": 67
}

Command Statistics (Admin Only)

GET /api/v1/stats/commands

Get command usage statistics.

Required Permission: ADMIN

Response:

{
  "total_commands_executed": 50000,
  "commands_executed_today": 1234,
  "commands_executed_this_week": 8567,
  "unique_commands_used": 45,
  "most_used_commands": [
    {
      "command": "look",
      "total_invocations": 15000,
      "invocations_today": 500,
      "invocations_this_week": 3200,
      "average_execution_time_ms": 2.5,
      "error_count": 0
    }
  ],
  "error_rate_percent": 0.5
}

Admin API

Broadcast Message

POST /api/v1/admin/broadcast

Broadcast a message to all connected players.

Required Permission: ADMIN

Request Body:

{
  "message": "Server maintenance in 10 minutes",
  "prefix": "[ADMIN]"
}

Response:

{
  "success": true,
  "recipients": 42,
  "message": "[ADMIN] Server maintenance in 10 minutes"
}

Shutdown Server

POST /api/v1/admin/shutdown

Initiate graceful server shutdown.

Required Permission: ADMIN

Request Body:

{
  "delay_seconds": 300,
  "reason": "Scheduled maintenance",
  "broadcast_warning": true
}

Response:

{
  "success": true,
  "message": "Shutdown scheduled: Scheduled maintenance",
  "scheduled_at": "2024-01-15T10:35:00Z"
}

Reload Configuration

POST /api/v1/admin/reload-config

Reload server configuration from files.

Required Permission: ADMIN

Response:

{
  "success": true,
  "message": "Configuration reloaded successfully",
  "reloaded_sections": ["engine", "world"]
}

List API Keys

GET /api/v1/admin/api-keys

List all API keys.

Required Permission: ADMIN

Query Parameters:

Parameter Type Default Description
include_inactive bool false Include revoked keys

Response:

{
  "keys": [
    {
      "key_id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "My Integration",
      "permissions": ["READ_PUBLIC", "READ_PLAYERS"],
      "created_at": "2024-01-15T10:30:00Z",
      "expires_at": null,
      "last_used": "2024-01-20T15:45:00Z",
      "created_by": "admin",
      "is_active": true,
      "rate_limit_rpm": 60
    }
  ],
  "total": 5
}

Create API Key

POST /api/v1/admin/api-keys

Generate a new API key.

Required Permission: ADMIN

Request Body:

{
  "name": "Bot Integration",
  "permissions": ["READ_PUBLIC", "READ_PLAYERS"],
  "expires_in_days": 365,
  "rate_limit_rpm": 120
}

Response (201):

{
  "key_id": "660e8400-e29b-41d4-a716-446655440001",
  "name": "Bot Integration",
  "permissions": ["READ_PUBLIC", "READ_PLAYERS"],
  "created_at": "2024-01-15T10:30:00Z",
  "expires_at": "2025-01-15T10:30:00Z",
  "last_used": null,
  "created_by": "admin-key",
  "is_active": true,
  "rate_limit_rpm": 120,
  "raw_key": "maid_660e8400_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

Important: The raw_key is only returned once. Store it securely.

Revoke API Key

DELETE /api/v1/admin/api-keys/{key_id}

Revoke an API key.

Required Permission: ADMIN

Response: 204 No Content


WebSocket Events

WebSocket /api/v1/events

Stream real-time game events.

Query Parameters:

Parameter Type Description
api_key str Optional API key for authentication
types str Comma-separated event types to subscribe to

Example Connection:

const ws = new WebSocket(
  'ws://localhost:8080/api/v1/events?api_key=maid_xxx&types=player_login,chat_message'
);

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Event:', data.type, data.data);
};

Event Types:

Type Description
player_login Player connected
player_logout Player disconnected
player_command Player executed a command
chat_message Chat message sent
system_message System message
combat Combat started
damage Damage dealt
death Entity died
respawn Entity respawned
world_event World event occurred
room_enter Entity entered a room
room_leave Entity left a room
entity_created Entity created
entity_destroyed Entity destroyed
component_added Component added to entity
component_removed Component removed from entity
tick Game tick (use sparingly)

Event Message Format:

{
  "type": "player_login",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "session_id": "xxx",
    "player_id": "yyy"
  }
}

Client Messages:

// Ping (server responds with pong)
{"type": "ping"}

// Update subscription
{"type": "subscribe", "types": ["combat", "chat_message"]}

Error Responses

All errors follow a consistent format:

{
  "detail": "Error message describing what went wrong"
}

HTTP Status Codes:

Code Description
400 Bad Request - Invalid input
401 Unauthorized - API key required
403 Forbidden - Insufficient permissions
404 Not Found - Resource does not exist
409 Conflict - Resource already exists
429 Too Many Requests - Rate limit exceeded
500 Internal Server Error
503 Service Unavailable - Engine not ready

Example: curl Commands

Health Check

curl http://localhost:8080/api/v1/health

List Online Players

curl "http://localhost:8080/api/v1/players?online_only=true" \
  -H "X-API-Key: maid_xxx_yyy"

Get Player Details

curl "http://localhost:8080/api/v1/players/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: maid_xxx_yyy"

Ban a Player

curl -X POST "http://localhost:8080/api/v1/players/550e8400.../ban" \
  -H "X-API-Key: maid_xxx_yyy" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Cheating", "duration_hours": 24}'

Broadcast Message

curl -X POST "http://localhost:8080/api/v1/admin/broadcast" \
  -H "X-API-Key: maid_xxx_yyy" \
  -H "Content-Type: application/json" \
  -d '{"message": "Server restart in 5 minutes"}'

Create API Key

curl -X POST "http://localhost:8080/api/v1/admin/api-keys" \
  -H "X-API-Key: maid_xxx_yyy" \
  -H "Content-Type: application/json" \
  -d '{"name": "Dashboard", "permissions": ["READ_PUBLIC", "READ_PLAYERS"]}'