Skip to content

Firewall, mail and notifications API

The host’s ufw. Every route needs a superuser. Responses are camelCase. See Change the firewall safely for how changes are applied and rolled back.

Method Path Body Returns
GET /firewall/ State: available, active, defaultIncoming, sshPorts, rules, webSources, refreshedAt, confirmWindow (seconds), open (the change in progress, or null), recent (last 20 changes)
GET /firewall/pending {open}: the change in progress, or null. The UI polls this from every page.
POST /firewall/refresh {detail: "Refresh requested."}. The state is also re-read every minute.
POST /firewall/rules Rule body The change (201), or 409 while another change is in progress
POST /firewall/rules/remove Rule body, matching a rule with origin: "panel" The change
POST /firewall/web-sources {preset: "cloudflare"} or {sources: "<list>"} The change
POST /firewall/enable The change
POST /firewall/disable The change
GET /firewall/changes/{id} The change
POST /firewall/changes/{id}/confirm The change. Only the requester, before confirmBy.
POST /firewall/changes/{id}/revert The change. Puts the old rules back now.
Field Values
action Required: allow, deny, reject, limit.
proto tcp, udp, any.
port "22", "8000:8100", or empty for every port.
from any, an IP address, or a CIDR.
note Up to 60 characters.

Each rule in the state has action, proto, port, from, comment, families and origin (panel, base, web or other). Only panel rules can be removed here.

sources for /web-sources is a list of IPs and CIDRs separated by commas, spaces or newlines. An empty list or any opens 80 and 443 to everyone. The request is refused if your address isn’t among the sources, or another rule still lets everyone in on 80 or 443.

id, op (add, delete, web-sources, enable, disable), rule, status, error, requestedBy, requestedByEmail, requesterIp, confirmBy, createdAt, finishedAt.

status: queued, applying, awaiting_confirmation, confirm_requested, revert_requested, applied, rolled_back, failed.

When to use: add the rule, wait for awaiting_confirmation, then confirm from a client that reaches the panel through the new rules. If you don’t confirm within FIREWALL_CONFIRM_MINUTES (default 5), the agent restores the old rules on its own.

Every route needs a superuser. Responses are camelCase.

Method Path Body Returns
GET /mail/status {installed}
POST /mail/install {detail: "Installation queued."}
GET /mail/health Cached health of the stack, with detail and the last repair’s lastRepairAt, lastRepairStatus, lastRepairDetail, lastRepairSteps
POST /mail/repair {detail: "Repair queued."}
GET /mail/domains {results}
POST /mail/domains {domain} (the apex, ≤ 253 characters) The domain
PATCH /mail/domains/{id} {mailHostname?, dmarcPolicy?}. dmarcPolicy is none, quarantine or reject. The domain
DELETE /mail/domains/{id} {detail}. Removes its mailboxes too.
GET /mail/domains/{id}/dns {domain, mailHostname, publicIp, dkimConfigured, records}
POST /mail/domains/{id}/sync {detail: "Sync queued."}
GET /mail/domains/{id}/accounts {results}: mailboxes
POST /mail/domains/{id}/accounts {localPart, password, quotaMb?} The mailbox
PUT /mail/accounts/{id}/password {password} The mailbox
DELETE /mail/accounts/{id} {detail: "Mailbox deleted."}

Domain fields: id, domain, mailHostname (default mail.<domain>), dkimSelector, dkimConfigured, dmarcPolicy, publicIp, isActive, createdAt. Mailbox fields: id, mailDomainId, address, quotaMb, isActive, createdAt, updatedAt, and connection with host, username and the smtp, imap and pop3 ports and security modes. Password hashes are never returned.

See Run a mail server.

The panel’s own outbound mail for alert emails. Superuser. Responses are rows (snake_case) without smtp_password.

Method Path Body Returns
GET /notifications/settings/smtp The settings
PUT /notifications/settings/smtp Any of {smtpHost, smtpPort, smtpUsername, smtpPassword, smtpSecurity, fromEmail, fromName, emailEnabled, alertEmail}. An empty smtpPassword keeps the stored one. The settings
POST /notifications/settings/smtp/test {toEmail} {detail: "Test email sent."}
Method Path Permission Returns
GET /notifications/host-stats Superuser {snapshot}: the latest whole-host CPU, memory and disk sample

Rules with scope: "app" follow the app’s team roles: any member can read them, a Developer can write them. Every other scope is superuser-only. Responses are rows (snake_case).

Method Path Body / query Returns
GET /notifications/rules Query scope?, appId?, postgresInstanceId?, mongoInstanceId?, managedServiceId?, applicationId? {results}
GET /notifications/rules/{id} The rule
POST /notifications/rules Rule fields The rule
PUT /notifications/rules/{id} {metric?, comparison?, thresholdPercent?, severity?, cooldownMinutes?, enabled?, notifyEmail?}. Scope and target can’t change. The rule
DELETE /notifications/rules/{id} {detail}
GET /notifications/events Same filters as rules, plus limit (default 50) {results}: fired alerts
Field Values
scope Required: app, system, postgres, mongo, mail, service, runtime.
Target appId (app), postgresInstanceId (postgres), mongoInstanceId (mongo), managedServiceId (service), applicationId (runtime). system and mail take none.
metric Required: cpu_percent, memory_percent, disk_percent, connections_percent, status_down.
thresholdPercent Required except for status_down. 0 to 100, or 0 to cores × 100 for cpu_percent.
comparison Default gte.
severity Default warning.
cooldownMinutes 1 to 1440, default 15.
enabled Default true.
notifyEmail Default true.

App alerts notify every member of the app’s team. Other scopes notify every active superuser.

Your own notifications. Authenticated. Rows (snake_case).

Method Path Query Returns
GET /notifications/inbox unreadOnly?, limit? (default 50), offset? {results, count}
GET /notifications/inbox/unread-count {count}
POST /notifications/inbox/{id}/read Marks one as read
POST /notifications/inbox/read-all Marks all as read