API Reference
Super exposes a RESTful API on port 9002 (default). All responses are in JSON format.
Authentication
Without security plugin loaded (OSS only): No API authentication. The API is open on the bind address. OSS ships with host = "127.0.0.1" and allow_insecure_public_bind = false; superd refuses startup on a non-loopback bind unless you set that flag to true. See Configuration — OSS security defaults.
Licensed ([license].key valid): security is bundled with every subscription and must load — otherwise superd refuses startup. API auth is always active when licensed. See Authentication — Licensed deployments require security.
With security plugin loaded: All API requests require Authorization: Bearer <token> (except /health, /metrics, and docs whitelist). Public bind is allowed because auth middleware is active. Config auth_secret bootstraps Access Tokens and stays usable until an Admin explicitly disables it. See Authentication.
Health & docs
- GET
/health— liveness (no auth) - GET
/api/docs— Swagger UI whenenable_docs = true(docs feature build) - GET
/api/v1/openapi.json— OpenAPI catalog (same docs gate / whitelist)
Programs
List Programs
Get a summary of all managed processes.
- GET
/api/v1/programs
Response:
[
{
"id": "a1b2c3d4-...",
"name": "api-server",
"status": "Running",
"pid": 12345,
"cpu_usage": 2.5,
"mem_usage": 10485760
}
]Create Program
Register a new process dynamically.
- POST
/api/v1/programs
Body:
{
"name": "worker-1",
"command": "./worker",
"autostart": true,
"autorestart": "unexpected",
"exitcodes": [0],
"startsecs": 10,
"retry_limit": 3
}| Field | Default | Description |
|---|---|---|
autorestart | unexpected | unexpected, true, or false (Supervisor-compatible) |
exitcodes | [0] | Exit codes treated as success when autorestart=unexpected |
startsecs | 10 | Seconds of stable run before exit resets retry counter |
Migration note:
autostartcontrols boot-time start only. To disable crash auto-restart, set"autorestart": "false".
Get Details
Get full configuration and state for a specific program.
- GET
/api/v1/programs/{id}
{id} is the program UUID (not the name). Resolve it from GET /api/v1/programs.
Update Program
Partially update an existing program. Only fields present in the body are changed; omitted fields are left unchanged.
- PUT
/api/v1/programs/{id}
Body (all fields optional):
{
"command": "/usr/local/bin/my-app",
"env": { "LOG_LEVEL": "debug" },
"autorestart": "unexpected",
"health_check": { "type": "http", "url": "http://127.0.0.1:8080/health" }
}| Field | Description |
|---|---|
name, command, args, cwd, user, group | Program identity and execution |
env, env_file | Environment (env_file = "" clears) |
autostart, retry_limit, autorestart, exitcodes, startsecs, stopsecs, priority | Restart / stop behaviour |
depends_on, health_check, hooks | Orchestration |
stdout_logfile, stderr_logfile | Custom log paths (must resolve under storage.log_dir) |
artifact | OTA binary update — see below |
cron | Cron expression — see Scheduled Tasks. |
resource_limits | 💎 Requires isolation plugin on Linux — stored in config always; enforced only when plugin is loaded |
Restart semantics: Updating
command,env, etc. persists config only — it does not restart a running process. CallPOST /api/v1/programs/{id}/restartexplicitly, or changeartifact.checksumto trigger an automatic OTA restart.
OTA update via API
When artifact.checksum differs from the stored value, Super starts the transactional OTA flow (download → verify → backup → swap → restart → health validate / rollback). See Atomic OTA Updates.
Step 1 — resolve UUID:
curl -s http://127.0.0.1:9002/api/v1/programs \
| jq -r '.[] | select(.name=="my-app") | .id'Step 2 — trigger update:
curl -X PUT "http://127.0.0.1:9002/api/v1/programs/${PROGRAM_ID}" \
-H "Content-Type: application/json" \
-d '{
"artifact": {
"source": "https://example.com/builds/v2.0.0/app-linux-amd64",
"checksum": "a1b2c3d4e5f6789abcdef0123456789abcdef0123456789abcdef0123456789",
"destination": "/usr/local/bin/my-app",
"extract": false,
"restart_policy": "immediate"
}
}'artifact field | Description |
|---|---|
source | Download URL |
checksum | Expected SHA256 hex digest |
destination | Path of the binary on disk |
extract | true if the download is an archive to extract |
restart_policy | "immediate" (swap then restart) — primary supported policy |
With security plugin: add -H "Authorization: Bearer <token>".
Response: 200 OK on success; 400 if the program is not found or validation fails.
Control Actions
Perform lifecycle actions.
- POST
/api/v1/programs/{id}/start - POST
/api/v1/programs/{id}/stop(Query param:?force=true) - POST
/api/v1/programs/{id}/restart
Historical Logs
Read the last N lines from on-disk log files ({uuid}.out / {uuid}.err).
- GET
/api/v1/programs/{id}/logs
Query parameters:
| Param | Default | Description |
|---|---|---|
tail | 200 | Lines from end of file (max 5000) |
source | both | stdout or stderr |
Response:
{
"id": "a1b2c3d4-...",
"logs": [
{ "source": "stdout", "content": "line-1\nline-2\n" },
{ "source": "stderr", "content": "error line\n" }
]
}Send Signal
- POST
/api/v1/programs/{id}/signal
Body:
{
"signal": "hup"
}System & Stack
Apply Stack (Declarative)
Update the entire system state to match a JSON definition.
- PUT
/api/v1/stack
Body:
{
"prune": true,
"services": [ ... list of program configs ... ]
}Shutdown
Gracefully stop the daemon (same for foreground and superd --daemon instances).
- POST
/api/v1/system/shutdown
System Stats
Host-level CPU and memory snapshot (refreshed every ~3s by the monitor thread).
- GET
/api/v1/system/stats
Response:
{
"cpu_percent": 12.4,
"memory_used_bytes": 4294967296,
"memory_total_bytes": 17179869184,
"timestamp": 1719820800
}Observability
Prometheus Metrics
Export metrics in Prometheus text format.
- GET
/metrics
Log Stream (WebSocket)
Stream stdout/stderr.
- WS
/ws?id={program_id}
Batch Operations
Perform actions on multiple programs simultaneously.
- POST
/api/v1/programs/batch
Body:
{
"target_ids": ["uuid-1", "uuid-2"], // Or omit and use "group_name": "backend"
"select_all": false,
"action": {
"type": "Restart" // Or "Start", "Stop", "Remove", "Signal"
}
}Security & Authentication (security plugin 💎)
Without the plugin: These routes are not registered. Requests return 404 Not Found.
Manage access tokens for API authorization. Bootstrap with config auth_secret; Admins may optionally disable it after creating an Admin token. See Authentication.
Login
- POST
/api/v1/auth/login
Logout
- POST
/api/v1/auth/logout
Auth status
- GET
/api/v1/auth/status
Disable auth_secret
- POST
/api/v1/auth/secret/disable
List Tokens
- GET
/api/v1/auth/tokens
Create Token
- POST
/api/v1/auth/tokens
Renew Token
- POST
/api/v1/auth/tokens/{id}/renew
Create Token body
{
"name": "ci-deploy-bot",
"role": "operator"
}Revoke Token
- DELETE
/api/v1/auth/tokens/{id}
System Configuration (licensed plugins 💎)
License route is served by OSS core when a valid
[license].keyis configured at startup.
Notify routes require thenotifyplugin; without it they return 404 Not Found.
Authentication: When the
securityplugin is loaded, protected routes (including license) require a valid Bearer token — same as other authenticated API calls.
Get License Info
- GET
/api/v1/system/license
Returns verified subscription metadata plus runtime plugin versions (versions are not part of the signed license claims).
Auth: Required when security plugin is active (Authorization: Bearer <token>).
Response 200:
{
"issued_to": "Customer Name",
"issued_at": 1710000000,
"major_version": 1,
"grants": ["security", "notify", "ui"],
"expires_at": 1741536000,
"license_id": "550e8400-e29b-41d4-a716-446655440000",
"features": ["auth", "notify", "dashboard"],
"plugin_versions": {
"security": "0.1.0",
"ui": "0.1.0"
}
}| Field | Notes |
|---|---|
expires_at | Omitted when license is perpetual (no expiry in claims) |
features | UI feature codes derived from authorized grants[] |
plugin_versions | Loaded plugin crate versions at runtime |
Errors: 404 if no license configured; 401 if auth required and missing/invalid token.
Manage Notifications
View or hot-reload webhook channels.
- GET
/api/v1/system/notify - PUT
/api/v1/system/notify - POST
/api/v1/system/notify/test