An async Python client library for the Unraid GraphQL API.
- 🔄 Async/await - Built with
aiohttpfor non-blocking operations - 🏠 Home Assistant ready - Accepts external
aiohttp.ClientSessionfor integration - 🔒 Secure by design - GraphQL variables, no string interpolation
- 📦 Typed - Full type hints with
py.typedmarker (PEP 561) - 🧩 Pydantic models - Structured response parsing
- 🔌 SSL auto-discovery - Handles Unraid's "No", "Yes", and "Strict" SSL modes
- ⚡ Redirect handling - Supports myunraid.net remote access
pip install unraid-apiimport asyncio
from unraid_api import UnraidClient
async def main():
async with UnraidClient("192.168.1.100", "your-api-key") as client:
# Test connection
if await client.test_connection():
print("Connected!")
# Get version info
version = await client.get_version()
print(f"Unraid {version['unraid']}, API {version['api']}")
asyncio.run(main())async with UnraidClient(host, api_key) as client:
# Custom GraphQL query
result = await client.query("""
query {
info {
os { hostname uptime }
cpu { name cores threads }
memory { total used }
}
}
""")
print(result["info"]["os"]["hostname"])async with UnraidClient(host, api_key) as client:
# Start a container
await client.start_container("container:plex")
# Stop a container
await client.stop_container("container:plex")
# Native restart when available; stop/wait/start on older schemas
await client.restart_container("container:plex")async with UnraidClient(host, api_key) as client:
# Start a VM
await client.start_vm("vm:windows-11")
# Stop a VM
await client.stop_vm("vm:windows-11")async with UnraidClient(host, api_key) as client:
# Start/stop array
await client.start_array()
await client.stop_array()
# Parity check
await client.start_parity_check(correct=True)
await client.pause_parity_check()
await client.resume_parity_check()
await client.cancel_parity_check()
# Disk spin control
await client.spin_up_disk("disk:1")
await client.spin_down_disk("disk:1")For an encrypted array, replace start_array() above with
start_array(decryption_password=password) or
start_array(decryption_keyfile=keyfile_contents). Keyfiles are data URLs or raw
base64 contents, not paths. Decryption values require an HTTPS connection;
HTTP destinations and redirects are rejected before transmitting them. Certificate
verification must be enabled. For private certificates, configure system trust
roots or SSL_CERT_FILE/SSL_CERT_DIR; encrypted starts enforce that trust even
when using an injected session. Configure the canonical HTTPS hostname and port
for encrypted starts: they bypass HTTP discovery, ignore cached destinations, and
reject redirects pointing at a different server or port.
import aiohttp
from unraid_api import UnraidClient
async def setup_client(session: aiohttp.ClientSession):
"""Use shared session from Home Assistant."""
client = UnraidClient(
host="192.168.1.100",
api_key="your-api-key",
session=session, # Injected session won't be closed by client
verify_ssl=False,
)
return clientasync with UnraidClient(host, api_key) as client:
# Stream CPU metrics
async for cpu in client.subscribe_cpu_metrics():
print(f"CPU: {cpu.percentTotal}%")
# Stream Docker container stats
async for stats in client.subscribe_container_stats("container:plex"):
print(f"CPU: {stats.cpuPercent}%, Mem: {stats.memUsage}")
# Generic subscription with custom query
async for data in client.subscribe("subscription { arraySubscription { state } }"):
print(f"Array state: {data['state']}")A subscription that receives no message for timeout * 10 seconds (300 s with the default timeout=30) raises UnraidTimeoutError. This is normal for rare events on a quiet server, such as notifications or UPS changes; catch it and reconnect.
Response data can be parsed into typed models:
from unraid_api.models import DockerContainer, VmDomain, UnraidArray
# Parse container data
container = DockerContainer(**container_data)
print(f"{container.name}: {container.state}")
# Parse array data
array = UnraidArray(**array_data)
print(f"Array: {array.state}, Capacity: {array.capacity.usage_percent}%")from unraid_api import UnraidClient
from unraid_api.exceptions import (
UnraidAPIError,
UnraidAuthenticationError,
UnraidConnectionError,
UnraidSSLError,
UnraidTimeoutError,
)
async with UnraidClient(host, api_key) as client:
try:
await client.query("query { online }")
except UnraidAuthenticationError:
print("Invalid API key")
except UnraidSSLError:
print("SSL certificate verification failed")
except UnraidConnectionError:
print("Cannot reach server")
except UnraidTimeoutError:
print("Request timed out")
except UnraidAPIError as e:
print(f"API error: {e}")| Method | Description |
|---|---|
test_connection() |
Test if server is reachable |
get_version() |
Get Unraid and API version |
supports_standby_safe_temperature_metrics(version=None) |
True for API >= 4.37.6; unknown versions fail closed |
get_server_info() |
Get server info for device registration |
query(query, variables) |
Execute GraphQL query |
mutate(mutation, variables) |
Execute GraphQL mutation |
| Method | Returns | Description |
|---|---|---|
get_system_metrics() |
SystemMetrics |
CPU, memory, temperature, power, uptime |
get_system_metrics_safe() |
SystemMetrics |
Same as above but omits temperature sensors to avoid waking sleeping disks |
typed_get_array() |
UnraidArray |
Array state, capacity, disks |
typed_get_containers() |
list[DockerContainer] |
All Docker containers |
typed_get_containers_safe() |
list[DockerContainer] |
Same as above but omits expensive fields (container sizes, mounts, network settings) — use for frequent polling |
typed_get_vms() |
list[VmDomain] |
All virtual machines |
typed_get_ups_devices() |
list[UPSDevice] |
UPS devices with battery info |
typed_get_shares() |
list[Share] |
User shares with usage |
get_notification_overview() |
NotificationOverview |
Notification counts |
typed_get_vars() |
Vars |
System configuration variables |
typed_get_registration() |
Registration |
License information |
typed_get_services() |
list[Service] |
System services status |
typed_get_flash() |
Flash |
Flash drive info |
typed_get_owner() |
Owner |
Owner information |
typed_get_plugins() |
list[Plugin] |
Installed API plugins |
typed_get_docker_networks() |
list[DockerNetwork] |
Docker networks |
typed_get_log_files() |
list[LogFile] |
Available log files |
typed_get_cloud() |
Cloud |
|
typed_get_connect() |
Connect |
|
typed_get_remote_access() |
RemoteAccess |
|
get_container_update_statuses() |
list[ContainerUpdateStatus] |
Docker container update availability |
get_ups_configuration() |
UPSConfiguration |
UPS hardware/software configuration |
get_display_settings() |
DisplaySettings |
Display and temperature settings |
get_docker_port_conflicts() |
DockerPortConflicts |
Docker LAN port conflicts |
get_temperature_metrics() |
TemperatureMetrics |
Temperature sensors, thresholds, summary |
get_network_metrics() |
list[NetworkMetrics] |
Per-interface network throughput, packet, error counters (API 4.35.0+) |
Unraid API >= 4.37.6 respects disk standby when reading metrics.temperature
or streaming systemMetricsTemperature. Earlier APIs wake sleeping disks.
At setup, call check_compatibility() (or get_version()) once and pass the
result to supports_standby_safe_temperature_metrics(version). For ha-unraid
and other consumers, a True result allows polling get_system_metrics() and
enabling temperature sensors. Otherwise use get_system_metrics_safe().
version = await client.check_compatibility()
if await client.supports_standby_safe_temperature_metrics(version):
metrics = await client.get_system_metrics()
else:
metrics = await client.get_system_metrics_safe()The helper compares only the API version, fails closed on unknown versions and
does not cache. Recheck the version after reconnecting or upgrading the API plugin.
Continue to avoid polling get_physical_disks(), even with include_smart=False:
that query still wakes disks on 4.37.6 pending
unraid/api#2105. Use get_array_disks().
restart_container() returns raw docker.restart data on the native path or
docker.start data on the fallback path. Its delay argument applies only to
the fallback. If introspection fails, permissive capabilities optimistically
attempt native restart. typed_get_vms() requests uuid only when introspection confirms support;
unknown schemas omit it to preserve VM listing.
Plugin and language installs modify the server. Follow their returned operation
with subscribe_plugin_install_updates(operation.id). remove_array_disk()
emits DeprecationWarning and rejects servers without the retired mutation;
use the Unraid Core storage workflow instead.
| Method | Returns | Description |
|---|---|---|
get_array_status() |
dict |
Array state and capacity |
get_disks() |
list[dict] |
Physical disks |
get_shares() |
list[dict] |
User shares |
get_containers() |
list[dict] |
Docker containers |
get_vms() |
list[dict] |
Virtual machines |
get_ups_status() |
list[dict] |
UPS devices |
get_notifications() |
list[dict] |
Notifications |
get_parity_history() |
list[dict] |
Parity check history |
get_services() |
list[dict] |
System services |
get_plugins() |
list[dict] |
Installed plugins |
get_docker_networks() |
list[dict] |
Docker networks |
get_log_files() |
list[dict] |
Log files |
get_log_file(path) |
dict |
Log file contents |
| Method | Description |
|---|---|
start_container(id) |
Start Docker container |
stop_container(id) |
Stop Docker container |
restart_container(id) |
Native Docker restart when supported; stop/wait/start fallback on older servers |
start_vm(id) |
Start VM |
stop_vm(id) |
Stop VM (graceful) |
force_stop_vm(id) |
Force stop VM |
pause_vm(id) |
Pause VM |
resume_vm(id) |
Resume paused VM |
start_array(decryption_password=..., decryption_keyfile=...) |
Start disk array; optional password or keyfile contents (data URL/base64, not a path) |
stop_array() |
Stop disk array |
remove_array_disk(id) |
Deprecated: direct removal was retired upstream; use Unraid Core storage workflows |
install_plugin(url, name=..., forced=...) |
Install plugin software; returns PluginInstallOperation |
install_language(url, name=..., forced=...) |
Install software from a language-pack URL, not a language code; returns PluginInstallOperation |
start_parity_check(correct) |
Start parity check |
pause_parity_check() |
Pause parity check |
resume_parity_check() |
Resume parity check |
cancel_parity_check() |
Cancel parity check |
spin_up_disk(id) |
Spin up disk |
spin_down_disk(id) |
Spin down disk |
update_container(id) |
Update container to latest image |
update_containers(ids) |
Update selected containers (API 4.35.0+) |
update_all_containers() |
Update every container with a pending update (API 4.35.0+) |
update_container_autostart(entries) |
Update container autostart configuration (API 4.37.0+) |
refresh_docker_digests() |
Re-check remote image digests ("check for updates", API 4.35.0+) |
| Method | Yields | Description |
|---|---|---|
subscribe(subscription, variables) |
dict |
Generic GraphQL subscription (async generator) |
subscribe_container_stats(container_id) |
DockerContainerStats |
Real-time Docker container resource metrics |
subscribe_cpu_metrics() |
CpuMetrics |
CPU usage per-core and total |
subscribe_cpu_telemetry() |
CpuTelemetryMetrics |
CPU power and temperature |
subscribe_memory_metrics() |
MemoryMetrics |
System memory usage |
subscribe_ups_updates() |
dict |
UPS state changes (raw) |
subscribe_array_updates() |
ArraySubscriptionUpdate |
Array state and capacity changes |
subscribe_temperature_metrics() |
TemperatureMetrics |
Temperature sensor updates |
subscribe_network_metrics() |
list[NetworkMetrics] |
Per-interface network metrics (API 4.35.0+) |
ServerInfo- Server info for HA device registrationSystemInfo- System informationSystemMetrics- CPU, memory, temperature, power, uptime metrics (includesTemperatureMetrics)Vars- System configuration variablesRegistration- License/registration infoFlash- Flash drive informationOwner- Server owner info
UnraidArray- Array state and disksArrayDisk- Individual array diskArrayCapacity- Capacity calculationsPhysicalDisk- Physical disk details (serialNum, firmwareRevision, partitions)DiskPartition- Disk partition info (name, fsType, size)Share- User share with usage and comment
DockerContainer- Container with ports, state, mounts, Tailscale, template portsDockerNetwork- Docker network configurationVmDomain- Virtual machine (id, name, state, optional uuid)TailscaleStatus- Tailscale hostname, DNS name, and online statusContainerTemplatePort- Template port configurationContainerUpdateStatus- Container update availabilityDockerPortConflicts- Port conflict detection
Service- System service statusUPSDevice- UPS with battery/power infoUPSConfiguration- UPS hardware/software configurationPlugin- Installed plugin infoLogFile- Log file metadataLogFileContent- Log file contentsDisplaySettings- Display and temperature threshold settingsKeyFile- Registration key file location and contents
Cloud- Unraid Connect cloud status (deprecated — removed from live API)Connect- Connect configuration (deprecated — removed from live API)RemoteAccess- Remote access settings (deprecated — removed from live API)
Notification- System notification (with link, type, formattedTimestamp)NotificationOverview- Notification countsNotificationOverviewCounts- Per-importance notification counts
CpuCore- Per-core CPU usage (percentTotal, percentUser, percentSystem, percentIdle, percentNice, percentIrq, percentGuest, percentSteal)CpuMetrics- CPU usage with per-core breakdownCpuTelemetryMetrics- CPU power and temperatureMemoryUtilization- Full memory data (total, used, free, available, active, buffcache, swap)MemoryMetrics- System memory total/used/freeArraySubscriptionUpdate- Array state and capacity updatesDockerContainerStats- Real-time container resource metricsTemperatureMetrics- Temperature sensors with summary and per-sensor dataTemperatureSensor- Individual sensor with reading, thresholds, and status helpersTemperatureReading- Temperature value, unit, and statusTemperatureSummary- Average, hottest, coolest, warning/critical countsSensorType- Enum: CPU_PACKAGE, CPU_CORE, DISK, NVME, CUSTOMTemperatureUnit- Enum: CELSIUS, FAHRENHEITTemperatureStatus- Enum: NORMAL, WARNING, CRITICAL, UNKNOWN
| Exception | Parent | Description |
|---|---|---|
UnraidAPIError |
Exception |
Base exception for all API errors |
UnraidConnectionError |
UnraidAPIError |
Connection failures |
UnraidSSLError |
UnraidConnectionError |
SSL certificate verification failures |
UnraidAuthenticationError |
UnraidAPIError |
Authentication failures (invalid API key) |
UnraidTimeoutError |
UnraidAPIError |
Request timeout |
Note: UnraidSSLError inherits from UnraidConnectionError, so it can be caught with either exception type for backwards compatibility.
- Python 3.11 or later, tested on 3.11–3.15
- Unraid 7.2.4+ with latest Unraid API
- API key with appropriate permissions
# Clone repository
git clone https://github.com/tinkerologie/unraid-api.git
cd unraid-api
# Install dependencies with uv
uv sync --all-extras
# Run tests
uv run pytest tests/ -v --cov=src/unraid_api
# Lint and type check
uv run ruff check .
uv run ruff format .
uv run mypy src/Apache License 2.0 - see LICENSE for details. Earlier releases were MIT licensed; see NOTICE.
Contributions welcome! Please ensure:
- Tests are written first (TDD)
- No linting errors (
ruff check . && mypy src/) - GraphQL variables used (no string interpolation)