Pankha Fan Control exposes a REST API for configuration and a WebSocket interface for real-time data. Base URL: http://<server-ip>:3143
Two kinds of identifiers appear in these routes:
Database IDs (numeric): :id for systems, and :sensorId / :fanId in label, visibility, and ordering routes.
Hardware IDs (string, e.g. it8628_fan_1): :fanId in the fan speed and calibration routes. IPMI agents use the zone ID here (e.g. cpu_zone).
All /api endpoints require a login session; requests without one get 401. Logging in via POST /api/auth/login sets a session cookie (httpOnly, SameSite) that browsers and same-origin requests carry automatically; command-line clients pass it with curl’s cookie flags (see Quick Examples). Sessions last 7 days by default, renewed by activity, and the duration is configurable with the PANKHA_SESSION_DURATION environment variable. Failed logins are rate limited. The WebSocket endpoint uses the same session cookie during connection.
On a fresh install no accounts exist yet: the dashboard walks you through creating the first admin account, or call POST /api/auth/setup directly.
Role Can do viewerRead everything: dashboard, systems, sensors, history. Cannot change anything. operatorEverything a viewer can, plus control: fan speeds, profiles, calibration, settings. adminEverything an operator can, plus user management, agent approval and deployment, fleet updates, and license changes.
Default rule: GET requests need viewer, all other methods need operator. Admin-only endpoints are marked in their tables. Agents are separate from user accounts - they authenticate their WebSocket connection with their own tokens, install scripts use short-lived deploy tokens, and agent binaries are public downloads.
Method Endpoint Description POST /api/auth/setupFirst-run only: create the initial admin account POST /api/auth/loginLog in; sets the session cookie POST /api/auth/logoutLog out; clears the session cookie GET /api/auth/meCurrent session: username, role, whether self-registration is enabled PUT /api/auth/passwordChange your own password (any role) GET /api/auth/usersList users (admin) POST /api/auth/usersCreate a user with a role (admin) PUT /api/auth/users/:idUpdate a user’s role or reset their password (admin) DELETE /api/auth/users/:idDelete a user; the last admin cannot be deleted (admin) GET /api/auth/registrationRead the self-registration setting (admin) PUT /api/auth/registrationEnable or disable self-registration and set its default role (admin) POST /api/auth/registerCreate your own account, available when self-registration is enabled
Method Endpoint Description GET /healthBackend health check with service statistics GET /api/overviewAggregate stats across all systems GET /api/websocket/infoWebSocket connection info and stats POST /api/emergency-stopForce all fans to 100% on all systems
Method Endpoint Description GET /api/systemsList all registered agents POST /api/systemsAdd new system GET /api/systems/limitGet agent limit info (current count, tier limit) GET /api/systems/:idGet system details with sensors/fans PUT /api/systems/:idUpdate system configuration DELETE /api/systems/:idRemove system GET /api/systems/:id/statusReal-time connection status GET /api/systems/:id/diagnosticsGet hardware diagnostics from agent
New agents wait for admin approval before they register as systems.
Method Endpoint Description GET /api/systems/pendingList agents awaiting approval POST /api/systems/pending/:agentId/approveApprove an agent; it registers and goes live DELETE /api/systems/pending/:agentIdDismiss a pending agent
Method Endpoint Description GET /api/systems/controller/statusFan profile controller status PUT /api/systems/controller/intervalSet controller update interval
Method Endpoint Description GET /api/systems/:id/sensorsGet all sensors for system PUT /api/systems/:id/sensors/:sensorId/labelSet custom sensor label PUT /api/systems/:id/sensors/:sensorId/visibilityShow/hide sensor ({ is_hidden }) GET /api/systems/:id/sensor-visibilityGet visibility settings PUT /api/systems/:id/sensor-groups/:groupName/visibilityShow/hide sensor group GET /api/systems/:id/sensor-orderGet custom sensor display order PUT /api/systems/:id/sensors/orderReorder sensors within a group PUT /api/systems/:id/sensor-groups/orderReorder sensor groups
Method Endpoint Description GET /api/systems/:id/fansGet all fans for system PUT /api/systems/:id/fans/:fanIdSet fan speed ({ speed: 0-100 })PUT /api/systems/:id/fans/:fanId/labelSet custom fan label PUT /api/systems/:id/fans/:fanId/visibilityShow/hide fan ({ is_hidden })
Manual speed commands return 409 while the fan is locked by a running calibration.
Method Endpoint Description GET /api/systems/:id/calibrationsCalibration snapshot for all fans on a system GET /api/systems/:id/fans/:fanId/calibrationCurrent calibration facts for one fan GET /api/systems/:id/fans/:fanId/calibration/historyPast calibration runs (trend data) POST /api/systems/:id/fans/:fanId/calibrateStart a manual calibration run (409 if offline) POST /api/systems/:id/fans/:fanId/stalls/clearClear the fan’s unexpected-stop log
See Calibration & Health for what these measurements mean.
Method Endpoint Description PUT /api/systems/:id/update-intervalSet agent polling interval (seconds) PUT /api/systems/:id/fan-stepSet fan speed step % (smoothing) PUT /api/systems/:id/hysteresisSet temperature hysteresis (°C) PUT /api/systems/:id/emergency-tempSet emergency temperature threshold PUT /api/systems/:id/failsafe-speedSet failsafe fan speed (0-100%) PUT /api/systems/:id/enable-fan-controlEnable/disable fan control PUT /api/systems/:id/log-levelSet agent log level PUT /api/systems/:id/nameSet agent display name POST /api/systems/:id/updateTrigger remote agent self-update
Method Endpoint Description GET /api/systems/settingsGet all backend settings GET /api/systems/settings/:keyGet a specific setting by key PUT /api/systems/settings/:keyUpdate a setting ({ "value": "..." })
Allowed setting keys: controller_update_interval, graph_history_hours, data_retention_days, accent_color, hover_tint_color, hardware_prune_days, fan_recalibration_days, ui_font_primary, ui_font_secondary, ui_font_scale, hub_log_level
Method Endpoint Description PUT /api/systems/:id/profileAssign profile to system POST /api/systems/:id/profilesCreate system-specific profile GET /api/systems/:id/historyHistorical data (start_time, end_time, sensor_ids, fan_ids, limit) GET /api/systems/:id/chartsGet aggregated chart data
Method Endpoint Description GET /api/fan-profilesList all profiles GET /api/fan-profiles/:idGet profile details POST /api/fan-profilesCreate new profile PUT /api/fan-profiles/:idUpdate profile DELETE /api/fan-profiles/:idDelete profile GET /api/fan-profiles/statsProfile statistics POST /api/fan-profiles/assignAssign profile to fan GET /api/fan-profiles/assignments/:systemIdGet fan assignments POST /api/fan-profiles/calculate-speedCalculate speed for temp GET /api/fan-profiles/exportExport profiles to JSON POST /api/fan-profiles/importImport profiles from JSON GET /api/fan-profiles/defaultsList available default profiles POST /api/fan-profiles/load-defaultsLoad default profiles into database
User-defined categories for organizing profiles (built-in types like silent and performance are system types and cannot be changed).
Method Endpoint Description GET /api/fan-profile-typesList all types with is_system flag and use count POST /api/fan-profile-typesCreate a type ({ name }, 409 on name collision) PATCH /api/fan-profile-types/:nameRename a user-defined type DELETE /api/fan-profile-types/:nameDelete an unused user-defined type
Method Endpoint Description GET /api/fan-configurations/:systemIdGet fan configurations POST /api/fan-configurations/sensorConfigure fan sensor mapping
Combine real sensors into a computed one (see Dashboard for the feature itself). A virtual sensor is referenced by other APIs as __virtual__<id>.
Method Endpoint Description GET /api/virtual-sensors/:systemIdList virtual sensors for a system GET /api/virtual-sensors/:id/usageWhere this virtual sensor is used (fan assignments) POST /api/virtual-sensorsCreate ({ system_id, name, operation: max|avg|median, sensor_ids }, minimum 2 sensors) PUT /api/virtual-sensors/orderReorder virtual sensors PUT /api/virtual-sensors/:idUpdate name, operation, or members DELETE /api/virtual-sensors/:idDelete a virtual sensor
Method Endpoint Description POST /api/discovery/scanScan network for agents GET /api/discovery/hardwareGet discovered hardware POST /api/discovery/test-fanTest fan control GET /api/discovery/systems/:id/sensors/scanScan for new sensors PUT /api/discovery/systems/:id/sensors/:sensorIdUpdate discovered sensor POST /api/discovery/systems/:id/sensor-mappingMap sensors to labels
Method Endpoint Description POST /api/deploy/templatesGenerate a deployment token (expires in 24h) GET /api/deploy/linuxServe dynamic Linux install script (?token=<token>) GET /api/deploy/ipmiServe dynamic IPMI install script (?token=<token>) GET /api/deploy/hub/statusStatus of locally cached agent binaries POST /api/deploy/hub/stageDownload a specific agent version to the hub DELETE /api/deploy/hub/clearClear all locally cached agent binaries GET /api/deploy/binaries/:agentType/:archServe cached binary (os_linux/ipmi_host, x86_64/aarch64) GET /api/deploy/binaries/:archServe cached OS agent binary (legacy form)
Vendor profiles that teach the IPMI agent how to talk to a server’s BMC.
Method Endpoint Description GET /api/deploy/profilesVendor/model catalog for profile selection GET /api/deploy/profiles/refreshRe-scan profile files on disk GET /api/deploy/profiles/assigned/:agentIdResolved profile assigned to an agent PUT /api/deploy/profiles/assign/:agentIdAssign a profile to an agent POST /api/deploy/profiles/customSave a custom profile from the Profile Builder GET /api/deploy/profiles/:vendor/:modelGet one profile definition
Method Endpoint Description POST /api/systems/:id/execute-raw-ipmiRun a raw IPMI command on an agent (profile testing)
Method Endpoint Description GET /api/config/deploymentGet deployment config (hub IP and port)
Method Endpoint Description GET /api/licenseGet current license info (tier, limits, expiration) POST /api/licenseActivate license key DELETE /api/licenseRemove license (revert to free tier) GET /api/license/pricingGet tier pricing info POST /api/license/syncForce sync with license server (check for renewals)
Endpoint : ws://<server-ip>:3143/websocket
Message Description subscribeSubscribe to topics (e.g. systems:all) unsubscribeUnsubscribe from topics requestFullSyncRequest a complete state snapshot getSystemDataRequest one system’s current data getOverviewRequest aggregate stats pingKeep-alive check
Event Description fullStateComplete snapshot (on connect / full sync) systemDeltaIncremental updates (only changed values) systemOfflineAgent disconnected agentRegisteredAgent connected agentUnregisteredAgent stopped gracefully agentErrorAgent reported a hardware error agentRecoveredAgent recovered from an error state agentConfigUpdatedConfig change (immediate broadcast) fanCalibrationStatusCalibration run lifecycle (running/done/failed) fanStalledStall watchdog: fan read 0 RPM while commanded to spin fanStallClearedStall condition cleared commandCompletedA dispatched agent command finished commandFailedA dispatched agent command failed licenseUpdatedLicense changed on the backend (refetch /api/license)
"agentId" : " linux-agent-1 " ,
"timestamp" : " 2025-01-01T12:00:00Z " ,
"changes" : [ " sensors " , " fans " ],
"sensors" : [{ "id" : " temp1 " , "temperature" : 45.2 }],
"fans" : [{ "id" : " fan1 " , "rpm" : 1200 , "speed" : 40 }]
# Saves the session cookie to cookies.txt; -b cookies.txt sends it on later calls
curl -c cookies.txt -X POST http://localhost:3143/api/auth/login \
-H " Content-Type: application/json " \
-d ' {"username": "admin", "password": "your-password"} '
curl -b cookies.txt -X PUT http://localhost:3143/api/systems/1/fans/it8628_fan_1 \
-H " Content-Type: application/json " \
curl -b cookies.txt -X POST http://localhost:3143/api/virtual-sensors \
-H " Content-Type: application/json " \
"name": "CPU + NVMe Max",
"sensor_ids": [12, 15, 18]
curl -b cookies.txt -X POST http://localhost:3143/api/systems/1/fans/it8628_fan_1/calibrate
curl http://localhost:3143/health
"error" : " Error message " ,
"message" : " Detailed description "
Code Meaning 200 Success 201 Created 400 Bad request 401 Not logged in (missing or expired session - log in first) 403 Forbidden (role too low / license limit / read-only mode) 404 Not found 409 Conflict (system offline, calibration lock, name collision) 500 Server error 503 Service unavailable
URL Parameters : Replace :id, :fanId, etc. with actual values (see the identifier note at the top of this page).