Argus Documentation

Self-hosted power monitoring for UPS devices, PDUs, and sensors with full observability stack integration

View project on GitHub

πŸ”Œ API Reference

Complete REST API documentation for the Argus FastAPI backend.


πŸ”— Base URL

http://localhost:8000/api

Replace localhost:8000 with your server address.


πŸ”‘ Authentication

API Key Authentication

When API_KEY is set, protected endpoints require an X-Api-Key header:

curl -X POST http://localhost:8000/api/trigger \
  -H "X-Api-Key: your-api-key-here"

Public endpoints (most GET requests) do not require authentication.

Generate a Secure API Key

# Option 1: Python secrets module (recommended)
python -c 'import secrets; print(secrets.token_urlsafe(32))'

# Option 2: OpenSSL
openssl rand -hex 32

Requirements:

  • Minimum 32 characters enforced at startup
  • Application exits with an error message if API_KEY is set but too short

Disabling Authentication

Leave API_KEY unset in .env. Not recommended for production.


🚦 Rate Limiting

Protected endpoints are rate-limited per API key:

  • Default: 60 requests per 60-second sliding window
  • Configurable: RATE_LIMIT_PER_MINUTE in .env
  • Response on limit: 429 Too Many Requests with Retry-After header
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json

{ "detail": "Rate limit exceeded. Try again in 60 seconds." }

🌐 Public Endpoints

🩺 Health Check

GET /api/health

Response:

{
  "status": "healthy",
  "scheduler_running": true,
  "uptime_seconds": 3600
}

πŸ“Š Snapshots

List Snapshots

GET /api/snapshots

Query parameters:

Parameter Type Default Description
page integer 1 Page number (β‰₯ 1)
page_size integer 50 Items per page (1–200)
device_id string (none) Filter by device ID

Response:

{
  "page": 1,
  "page_size": 50,
  "total": 1234,
  "items": [
    {
      "id": 1,
      "timestamp": "2026-05-27T10:00:00Z",
      "device_id": "ups-main",
      "device_type": "ups",
      "power_watts": 450.0,
      "load_percent": 55.0,
      "voltage": 120.0,
      "battery_percent": 100.0,
      "runtime_seconds": 3600.0,
      "ups_status": "OL",
      "temperature_c": null
    }
  ]
}

Latest Snapshot

GET /api/snapshots/latest

Returns the most recent snapshot (all devices) or filtered by ?device_id=.


πŸ”” Events

List Events

GET /api/events

Query parameters:

Parameter Type Default Description
page integer 1 Page number
page_size integer 50 Items per page (1–200)
device_id string (none) Filter by device
event_type string (none) Filter by type (e.g. on_battery)

Response:

{
  "page": 1,
  "page_size": 50,
  "total": 42,
  "items": [
    {
      "id": 1,
      "timestamp": "2026-05-27T09:00:00Z",
      "device_id": "ups-main",
      "event_type": "on_battery",
      "metadata": { "previous_status": "OL", "battery_percent": 100.0 }
    }
  ]
}

Event types:

Value Trigger
on_battery UPS switched from AC to battery
power_restored AC power returned
battery_low Battery charge below low threshold
shutdown_initiated Battery hit floor percentage (SHUTDOWN_BATTERY_FLOOR_PCT)
threshold_crossed Load % or temperature exceeded configured limit
device_offline Device missed DEVICE_OFFLINE_MISSED_POLLS consecutive polls
device_online Device reachable again after offline period

πŸ–₯️ Devices

List Devices

GET /api/devices

Response:

[
  {
    "id": "ups-main",
    "name": "Main UPS",
    "type": "ups",
    "poller": "nut",
    "host": "192.168.1.10",
    "port": 3493,
    "enabled": true,
    "connection_config": {},
    "model": "SmartUPS 1500",
    "firmware": "1.0.0",
    "serial": "ABC123",
    "manufacturer": "APC",
    "last_seen": "2026-05-27T10:00:00Z"
  }
]

Get Device

GET /api/devices/{device_id}

Returns 404 if the device does not exist.


⚑ Energy

GET /api/energy

Returns cumulative kWh totals per device. Requires energy in ENABLED_EXPORTERS.

Response:

[
  {
    "device_id": "ups-main",
    "kwh_total": 12.34,
    "cost_total": 1.85,
    "currency": "USD"
  }
]

▢️ Trigger Status

GET /api/trigger/status

Response:

{ "status": "idle", "message": "No poll in progress." }

πŸ” Diagnostics

GET /api/diagnostics

Returns last-poll diagnostics from the scheduler’s shared state (device counts, errors, timing).


πŸ”’ Protected Endpoints

All protected endpoints require X-Api-Key when API_KEY is set.

▢️ Trigger Manual Poll

POST /api/trigger
X-Api-Key: <key>

Response (202 Accepted):

{ "status": "accepted", "message": "Poll trigger queued." }

Returns 409 Conflict if a poll is already in progress.


βš™οΈ Configuration

Get Runtime Config

GET /api/config

Response:

{
  "poll_interval_minutes": 5,
  "enabled_exporters": ["sqlite"],
  "scanning_disabled": false,
  "scheduler_paused": false,
  "nut_host": "192.168.1.10",
  "nut_port": 3493
}

Update Runtime Config

PUT /api/config
X-Api-Key: <key>
Content-Type: application/json

{
  "poll_interval_minutes": 10,
  "enabled_exporters": ["sqlite", "prometheus"],
  "scanning_disabled": false,
  "scheduler_paused": false,
  "nut_host": "192.168.1.10",
  "nut_port": 3493
}

Changes take effect on the next poll cycle without a container restart.


πŸ”” Alerts

Get Alert Configuration

GET /api/alerts

Update Alert Configuration

PUT /api/alerts
X-Api-Key: <key>
Content-Type: application/json

{
  "providers": [
    {
      "type": "webhook",
      "enabled": true,
      "url": "https://hooks.example.com/argus",
      "min_severity": "medium"
    }
  ]
}

Test Alert Notification

POST /api/alerts/test
X-Api-Key: <key>

Sends a test notification through all enabled providers.


πŸ–₯️ Devices (write)

Add Device

POST /api/devices
X-Api-Key: <key>
Content-Type: application/json

{
  "id": "pdu-rack1",
  "name": "Rack 1 PDU",
  "type": "pdu",
  "poller": "snmp",
  "host": "192.168.1.20",
  "port": 161,
  "enabled": true,
  "connection_config": { "community": "public" }
}

Returns 409 Conflict if the device ID already exists.

Update Device

PUT /api/devices/{device_id}
X-Api-Key: <key>
Content-Type: application/json

Delete Device

DELETE /api/devices/{device_id}
X-Api-Key: <key>

Returns 404 if not found.

Replace All Devices

PUT /api/devices
X-Api-Key: <key>
Content-Type: application/json

[ { "id": "...", ... } ]

⚠️ Error Responses

Status Meaning
400 Bad Request Invalid request body or parameters
401 Unauthorized Missing or invalid X-Api-Key
404 Not Found Resource does not exist
409 Conflict Resource already exists (device) or poll in progress
413 Request Entity Too Large Body exceeds 1 MB
422 Unprocessable Entity Pydantic validation failed
429 Too Many Requests Rate limit exceeded
503 Service Unavailable SQLite database not reachable