API Reference
July 1, 2026 ยท View on GitHub
Overview
Muximux provides a REST API for managing configuration, apps, groups, health, authentication, icons, and themes. All endpoints return JSON.
When authentication is enabled, most endpoints require a valid session cookie or API key (X-Api-Key header). Write operations (POST, PUT, DELETE) require the admin role.
Authentication
| Endpoint | Method | Auth Required | Description |
|---|---|---|---|
/api/auth/login | POST | No | Login with username/password |
/api/auth/logout | POST | No | Logout (clears session) |
/api/auth/status | GET | No | Check auth status and current user |
/api/auth/me | GET | Yes | Get current user details |
/api/auth/password | POST | Yes | Change password (builtin auth only) |
/api/auth/users | GET | Admin | List all users |
/api/auth/users | POST | Admin | Create a new user |
/api/auth/users/{username} | PUT | Admin | Update user role/email/display name |
/api/auth/users/{username} | DELETE | Admin | Delete a user |
/api/auth/method | PUT | Admin | Switch authentication method |
/api/auth/api-key | GET | Admin | Report whether an instance API key is configured (never returns the key) |
/api/auth/api-key | POST | Admin | Generate or rotate the instance API key |
/api/auth/api-key | DELETE | Admin | Clear the instance API key |
/api/auth/setup | POST | No (but requires X-Setup-Token) | Initial setup (onboarding wizard). See Authentication > First-Run Setup for the token. |
/api/auth/oidc/login | GET | No | Redirect to OIDC provider |
/api/auth/oidc/callback | GET | No | OIDC callback handler |
Login request:
POST /api/auth/login
{
"username": "admin",
"password": "secretpassword"
}
Login response:
{
"success": true,
"user": {
"username": "admin",
"role": "admin",
"email": "admin@example.com",
"display_name": "Admin User"
}
}
Auth status response:
GET /api/auth/status
{
"authenticated": true,
"auth_method": "builtin",
"oidc_enabled": false,
"setup_required": false,
"user": {
"username": "admin",
"role": "admin",
"email": "admin@example.com",
"display_name": "Admin User"
}
}
The auth_method field returns the active authentication method: none, builtin, forward_auth, or oidc. The user field is only present when the request is authenticated. When auth_method is forward_auth and a logout URL is configured, the response includes a logout_url field for client-side redirect on sign-out.
API key authentication:
Non-browser integrations can authenticate with an API key via the X-Api-Key header, but only on allowlisted paths -- not every /api/* endpoint. Out of the box:
GET /api/appearance-- read Muximux's current theme + language (see Apps > Appearance API)- Any proxied-app path the operator has opted into via
auth_bypass: [{require_api_key: true}](see Apps > Per-App Auth Bypass)
Example, calling Sonarr through Muximux with a configured bypass:
GET /proxy/sonarr/api/v3/series
X-Api-Key: your-api-key-here
State-changing endpoints like /api/config, /api/apps, /api/themes, and /api/auth/users require a session cookie -- the API key will not work against them. See Authentication > API Key Authentication for the full scope and setup instructions.
User Management
List users:
GET /api/auth/users
Returns an array of users (without password hashes):
[
{"username": "admin", "role": "admin", "email": "admin@example.com", "display_name": "Admin User"},
{"username": "viewer", "role": "user", "email": "", "display_name": ""}
]
Create user:
POST /api/auth/users
{
"username": "newuser",
"password": "minimum8chars",
"role": "user",
"email": "user@example.com",
"display_name": "New User"
}
Validation: username is required, password must be at least 8 characters. Valid roles: admin, power-user, user. If the role is omitted or invalid, it defaults to user.
Update user:
PUT /api/auth/users/newuser
{
"role": "admin",
"email": "updated@example.com",
"display_name": "Updated Name"
}
All fields are optional -- only provided fields are updated.
Delete user:
DELETE /api/auth/users/newuser
Constraints: you cannot delete your own account, and you cannot delete the last admin user.
Auth Method Switching
Switch authentication method:
PUT /api/auth/method
{
"method": "forward_auth",
"trusted_proxies": ["192.168.0.0/16"],
"headers": {
"user": "Remote-User",
"email": "Remote-Email",
"groups": "Remote-Groups",
"name": "Remote-Name"
},
"logout_url": "https://auth.example.com/logout"
}
Valid methods: builtin, forward_auth, none. Switching to builtin requires at least one user to exist. Switching to forward_auth requires trusted_proxies. The optional logout_url configures where the browser redirects on sign-out to clear the auth provider's session. The change takes effect immediately without a restart.
Configuration
| Endpoint | Method | Role | Description |
|---|---|---|---|
/api/config | GET | Any | Get full configuration |
/api/config | PUT | Admin | Update full configuration |
/api/config/export | GET | Admin | Download config as YAML (sensitive data stripped) |
/api/config/import | POST | Admin | Parse and validate uploaded YAML, returns preview |
/api/config/restore | POST | Pre-setup only (requires X-Setup-Token) | Replace the live config with an uploaded YAML during first-run onboarding |
/api/appearance | GET | Any authenticated user, or any caller with X-Api-Key | Read-only snapshot of language + theme + colors for embedded apps |
The PUT endpoint accepts the full configuration object. Changes to most settings take effect immediately. Server-level settings (listen address, TLS, gateway) require a restart. Auth method changes can be made live via PUT /api/auth/method.
Export config:
GET /api/config/export
Returns a downloadable YAML file with password hashes, OIDC client secrets, and API keys removed. The filename includes the current date (e.g., muximux-config-2025-01-15.yaml).
Import config (preview):
POST /api/config/import
Content-Type: application/x-yaml
(YAML body, max 1 MB)
Validates the YAML and returns the parsed config as JSON for preview. The frontend can then apply it via PUT /api/config. Validation requires at least one app with a name and URL.
Restore config (first-run only):
POST /api/config/restore
Content-Type: application/x-yaml
X-Setup-Token: <token from server stdout or data/.setup-token>
(YAML body, max 1 MB)
Replaces the live config during the initial onboarding flow. Only accepted while the instance is in the pre-setup state; subsequent calls return 409 Conflict. Missing or invalid X-Setup-Token returns 401. See Authentication > First-Run Setup for how to find the token.
Appearance (read-only):
GET /api/appearance
Returns a JSON snapshot with language, theme (family, variant, id, is_dark), colors (a curated subset of CSS custom-property values), and theme_css_url. Embedded apps call this once on boot to sync their own styling with Muximux. See Apps > Appearance API for the full contract and usage examples.
Apps
| Endpoint | Method | Role | Description |
|---|---|---|---|
/api/apps | GET | Any | List all apps |
/api/apps | POST | Admin | Create a new app |
/api/app/{name} | GET | Any | Get app by name |
/api/app/{name} | PUT | Admin | Update app |
/api/app/{name} | DELETE | Admin | Delete app |
/api/app-action/{name} | POST | Per-app role gate | Fire the app's configured http_action HTTP request |
/api/app-docker/{name}/{start|stop|restart} | POST | Role-gated | Control a Docker-tracked container (requires lifecycle_enabled + :rw socket) |
Create app request:
POST /api/apps
{
"name": "Sonarr",
"url": "http://sonarr:8989",
"icon": {
"type": "dashboard",
"name": "sonarr"
},
"group": "Media",
"enabled": true,
"open_mode": "iframe"
}
Groups
| Endpoint | Method | Role | Description |
|---|---|---|---|
/api/groups | GET | Any | List all groups |
/api/groups | POST | Admin | Create a new group |
/api/group/{name} | GET | Any | Get group by name |
/api/group/{name} | PUT | Admin | Update group |
/api/group/{name} | DELETE | Admin | Delete group |
Discovery
| Endpoint | Method | Role | Description |
|---|---|---|---|
/api/discovery/docker/status | GET | Admin | Docker daemon reachability + discovery config |
/api/discovery/docker/networks | GET | Admin | List Docker networks for URL resolution |
/api/discovery/docker/config | PUT | Admin | Update discovery config (incl. auto_import mode, lifecycle_enabled) |
/api/discovery/docker/test | POST | Admin | Test a discovery config without saving |
/api/discovery/docker/scan | GET | Admin | Scan the daemon, return importable containers |
/api/discovery/docker/import | POST | Admin | Import selected containers as apps |
/api/discovery/docker/tracked | GET | Admin | List apps currently tracked from Docker |
/api/discovery/docker/track/{name} | DELETE | Admin | Detach an app from Docker tracking |
/api/discovery/docker/relink/probe | POST | Admin | Probe a container to re-link a detached app |
/api/discovery/docker/relink/confirm | POST | Admin | Confirm a re-link |
/api/discovery/docker-state | GET | Any | Current container-state map for tracked apps |
Auto-import is opt-in via discovery.docker.auto_import (off, add, update, or sync). The discovery configuration is also part of the full configuration object, so it can be set via PUT /api/config as well as PUT /api/discovery/docker/config.
Health
| Endpoint | Method | Description |
|---|---|---|
/api/health | GET | Simple health probe (for load balancers) |
/api/apps/health | GET | Get health status for all apps |
/api/apps/{name}/health | GET | Get health status for one app |
/api/apps/{name}/health/check | POST | Trigger immediate health check |
The /api/health endpoint always returns 200 OK when the server is running. It is intended for use with load balancers and uptime monitors.
Health status response:
{
"name": "Sonarr",
"status": "healthy",
"response_time_ms": 42,
"last_check": "2024-01-15T10:30:00Z",
"uptime_percent": 99.8,
"check_count": 1440,
"success_count": 1437
}
Status values:
healthy-- Last check received an HTTP 2xx responseunhealthy-- Last check failed (error, timeout, or non-2xx response)unknown-- App has not been checked yet
Icons
| Endpoint | Method | Role | Description |
|---|---|---|---|
/api/icons/dashboard | GET | Any | List dashboard icons |
/api/icons/dashboard/{name} | GET | Any | Get dashboard icon metadata |
/api/icons/lucide | GET | Any | List Lucide icons |
/api/icons/lucide/{name} | GET | Any | Get Lucide icon SVG |
/api/icons/custom | GET | Any | List custom icons |
/api/icons/custom | POST | Admin | Upload custom icon (multipart, 2MB limit) |
/api/icons/custom/fetch | POST | Admin | Download icon from URL and save locally |
/api/icons/custom/{name} | DELETE | Admin | Delete custom icon |
Upload custom icon:
Send a multipart form request with the icon file:
POST /api/icons/custom
Content-Type: multipart/form-data
file: (binary data)
Accepted formats: PNG, SVG, JPG, WebP, GIF. Maximum file size: 2MB.
Fetch icon from URL:
Download an image from a remote URL and save it as a custom icon:
POST /api/icons/custom/fetch
Content-Type: application/json
{
"url": "https://example.com/icon.png",
"name": "my-icon" // optional, derived from URL if omitted
}
The server downloads the image, validates the content type and size (2MB limit), and stores it locally. Returns {"name": "my-icon", "status": "uploaded"} on success.
Themes
| Endpoint | Method | Role | Description |
|---|---|---|---|
/api/themes | GET | Any | List all themes |
/api/themes | POST | Admin | Save custom theme |
/api/themes/{name} | DELETE | Admin | Delete custom theme |
Logs
| Endpoint | Method | Auth Required | Description |
|---|---|---|---|
/api/logs/recent | GET | Admin | Get recent log entries from the in-memory buffer (audit entries, client IPs, and panic stacks make this admin-only) |
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 200 | Maximum number of entries to return |
level | string | Filter by log level (debug, info, warn, error) | |
source | string | Filter by source tag (http, audit, server, auth, health, proxy, websocket, caddy, config, icons, themes, discovery, gateway, system) |
Example:
GET /api/logs/recent?limit=50&level=error
Response:
[
{
"timestamp": "2026-01-01T12:00:00Z",
"level": "INFO",
"message": "HTTP request",
"source": "http",
"attrs": {
"method": "GET",
"path": "/api/config",
"status": "200",
"latency_ms": "12",
"request_id": "a1b2c3d4e5f6a7b8"
}
}
]
Logs are stored in a 1000-entry ring buffer. When the buffer is full, the oldest entries are dropped. Entries are also broadcast in real-time via WebSocket (see below).
System
| Endpoint | Method | Auth Required | Description |
|---|---|---|---|
/api/system/info | GET | Yes | Get system information (admin-only fields like data_dir, environment, and uptime are scrubbed for non-admin callers) |
/api/system/updates | GET | Admin | Check for available updates |
System info response:
{
"version": "3.0.0",
"commit": "abc1234",
"build_date": "2025-01-15T00:00:00Z",
"go_version": "go1.26.0",
"os": "linux",
"arch": "amd64",
"uptime": "2d 5h 30m",
"environment": "docker"
}
Update check response:
{
"current_version": "3.1.1",
"latest_version": "3.2.0",
"update_available": true,
"release_url": "https://github.com/mescon/Muximux/releases/tag/v3.2.0",
"changelog": "..."
}
Proxy Status
| Endpoint | Method | Description |
|---|---|---|
/api/proxy/status | GET | Get Caddy proxy status |
Response:
{
"enabled": true,
"running": true,
"tls": true,
"domain": "muximux.example.com"
}
Gateway
The declarative server.gateway_sites: model is the current gateway path (the legacy Caddyfile was removed in 3.1.0).
| Endpoint | Method | Role | Description |
|---|---|---|---|
/api/gateway/sites | GET | Admin | List configured gateway sites |
/api/gateway/sites | POST | Admin | Create a gateway site |
/api/gateway/sites/{domain} | PUT | Admin | Update a gateway site |
/api/gateway/sites/{domain} | DELETE | Admin | Delete a gateway site |
/api/gateway/validate | POST | Admin | Validate a gateway site config without saving |
/api/auth/forward is the internal forward-auth verify endpoint used by the gateway to gate access. It is not meant to be called directly from a browser (a direct hit returns 400).
WebSocket
| Endpoint | Protocol | Description |
|---|---|---|
/ws | WebSocket | Real-time event stream |
Connect to /ws to receive real-time updates. Events are sent as JSON messages:
{"type": "config_updated", "payload": {...}}
{"type": "health_changed", "payload": [...]}
{"type": "app_health_changed", "payload": {"app": "Sonarr", "health": {"status": "healthy", ...}}}
Event types:
| Type | Payload | Description |
|---|---|---|
config_updated | Full config object | Configuration was changed (via Settings panel or API) |
health_changed | Array of health statuses | Health status changed for one or more apps |
app_health_changed | {"app": "name", "health": {...}} | Health status changed for a specific app |
docker_state_changed | {"app_name": "name", "state": {...}} | Container state changed for a Docker-tracked app (status, health, restart count, etc.) |
log_entry | LogEntry object | A new log entry was recorded (see Logs section above). Admin-only: only broadcast to admin clients |
The WebSocket client automatically reconnects if the connection drops, using exponential backoff (up to 30 seconds between retries, max 10 attempts).
Rate Limiting
The following endpoints are rate-limited to 5 attempts per IP address per minute to prevent brute-force attacks. If the limit is exceeded, the endpoint returns HTTP 429 (Too Many Requests).
POST /api/auth/login-- Login attemptsPOST /api/auth/setup-- Initial setup attemptsGET /api/auth/oidc/login-- OIDC login redirects (shares the login limiter)
Other API endpoints are not rate-limited.