Five markdown documents covering the full panel: - docs/README.md: index with links to all guides - docs/install.md: requirements, one-liner install, file layout, config.ini, auto-deploy, upgrade - docs/admin-guide.md: all admin panel sections (accounts, DNS, mail, security, Docker, notifications, WHMCS) - docs/reseller-guide.md: account management, white-label branding, Docker quotas - docs/user-guide.md: files, email, databases, FTP, DNS, SSL, cron, Docker, settings - docs/api-reference.md: all 25+ endpoints with request/response shapes, auth, rate limits, role access Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
NovaCPX — API Reference
Overview
All API endpoints are served under /api/<resource>/<action>.
Base URL pattern: https://<server>:<port>/api/<resource>/<action>
The same API is available on all three panel ports (8880, 8881, 8882). Which actions succeed depends on the role of the authenticated session.
Authentication
All endpoints (except auth/login) require an active session cookie ncpx_session. Obtain it by calling auth/login.
POST /api/auth/login
Content-Type: application/json
{"username": "admin", "password": "Nova2026!!"}
The response sets the ncpx_session cookie. Include it in all subsequent requests (credentials: 'include' in fetch, or -b cookies.txt in curl).
Response format
Every response is JSON:
{
"success": true,
"message": "OK",
"data": { ... }
}
On error:
{
"success": false,
"message": "Reason",
"errors": []
}
Paginated responses include a meta block:
{
"success": true,
"data": { "items": [...], "meta": { "total": 100, "page": 1, "per_page": 25, "pages": 4 } }
}
Role access
| Role | Panels | Access |
|---|---|---|
admin |
8882 | Everything |
reseller |
8881 | Own accounts + reseller features |
user |
8880 | Own account only |
Rate limiting
| Scope | Limit |
|---|---|
Login (auth/login) |
10 requests / minute |
| All other endpoints | 120 requests / minute |
Exceeded limits return HTTP 429 with Retry-After and X-RateLimit-* headers.
auth
POST /api/auth/login
Authenticate and create a session.
Body: {username, password}
Returns: {user: {id, username, role}, portal_url}
Access: Public
GET /api/auth/me
Return the current session's user object.
Returns: {id, username, email, role}
Access: Any authenticated user
POST /api/auth/logout
Destroy the current session.
Access: Any authenticated user
POST /api/auth/change-password
Change the current user's own password.
Body: {current_password, new_password, confirm_password}
Access: Any authenticated user
accounts
GET /api/accounts/list
List hosting accounts.
Query params: page, per_page, search, status
Returns: Paginated list with domain_count, email_count, db_count per account
Access: Admin (all accounts), Reseller (own accounts)
GET /api/accounts/get?id=<id>
Get a single account with its domains and disk usage.
Access: Admin, Reseller (own accounts)
POST /api/accounts/create
Create a hosting account. Creates Linux user, home directory, vhost, DNS zone, and optionally sends a welcome email.
Body:
{
"username": "john",
"domain": "example.com",
"email": "john@example.com",
"password": "secret",
"package_id": 1,
"php_version": "8.3"
}
Access: Admin, Reseller
POST /api/accounts/suspend
Suspend an account (disables vhost, notifies user).
Body: {id, reason?}
Access: Admin, Reseller (own accounts)
POST /api/accounts/unsuspend
Re-enable a suspended account.
Body: {id}
Access: Admin, Reseller (own accounts)
POST /api/accounts/terminate
Permanently delete an account and all its data.
Body: {id}
Access: Admin only
POST /api/accounts/change-password
Reset an account's panel and system password.
Body: {account_id, password}
Access: Admin only
GET /api/accounts/usage?id=<id>
Return disk, email, database, domain, and FTP usage vs. package limits.
Access: Admin, Reseller (own accounts)
domains
GET /api/domains/list?account_id=<id>
List domains for an account.
Access: Admin, Reseller (own accounts), User (own account)
POST /api/domains/add
Add a domain, subdomain, or redirect to an account.
Body:
{
"account_id": 1,
"domain": "example.com",
"type": "addon",
"document_root": "/home/user/public_html/example",
"php_version": "8.3"
}
type values: addon, subdomain, redirect
For redirects, include redirect_to (URL) and redirect_code (301 or 302).
Access: Admin, Reseller, User
POST /api/domains/remove
Remove a domain (cannot remove the primary domain).
Body: {account_id, domain_id}
Access: Admin, Reseller, User
GET /api/email/list?account_id=<id>
List email accounts for an account.
Access: Admin, Reseller, User
POST /api/email/create
Create a mailbox.
Body: {account_id, email, password, quota_mb?}
Access: Admin, Reseller, User (subject to max_email package limit)
DELETE /api/email/delete
Delete a mailbox.
Body: {id}
Access: Admin, Reseller, User
POST /api/email/suspend
Suspend a mailbox.
Body: {id}
Access: Admin, Reseller, User
GET /api/webmail/login-url?account_id=<id>&email=<email>
Generate a single-sign-on webmail URL (valid 5 minutes).
Access: Admin, Reseller, User
dns
GET /api/dns/list?account_id=<id>
List DNS zones for an account.
Access: Admin, Reseller, User
GET /api/dns/records?zone_id=<id>
List records in a zone.
POST /api/dns/add-record
Add a DNS record.
Body:
{
"zone_id": 1,
"type": "A",
"name": "www",
"value": "1.2.3.4",
"ttl": 3600
}
Access: Admin, Reseller, User
POST /api/dns/update-record
Update an existing record.
Body: {record_id, name, value, ttl}
POST /api/dns/delete-record
Delete a record.
Body: {record_id}
POST /api/dkim/generate
Generate DKIM key pair for a domain.
Body: {account_id, domain}
databases
GET /api/databases/list?account_id=<id>
List MySQL databases for an account.
Access: Admin, Reseller, User
POST /api/databases/create
Create a database and MySQL user.
Body: {account_id, db_name, db_user, db_pass}
Subject to max_databases package limit.
DELETE /api/databases/delete
Drop a database.
Body: {id}
ftp
GET /api/ftp/list?account_id=<id>
List FTP accounts.
POST /api/ftp/create
Create an FTP account.
Body: {account_id, username, password, home_dir}
Subject to max_ftp package limit.
DELETE /api/ftp/delete
Delete an FTP account.
Body: {id}
ssl
GET /api/ssl/list?account_id=<id>
List SSL certificates for an account.
POST /api/ssl/issue
Issue a Let's Encrypt certificate. The domain must resolve publicly.
Body: {account_id, domain}
POST /api/ssl/delete
Remove an SSL certificate record.
Body: {id}
files
The file manager API mirrors the user-facing file manager. All paths are validated against the account's home directory; paths outside it are rejected.
GET /api/files/list?account_id=<id>&path=<path>
List directory contents.
GET /api/files/read?account_id=<id>&path=<path>
Read a text file (max 1 MB).
POST /api/files/write
Write/create a file.
Body: {account_id, path, content}
POST /api/files/mkdir
Create a directory.
Body: {account_id, path}
DELETE /api/files/delete
Delete a file or directory.
Body: {account_id, path}
POST /api/files/rename
Rename or move a file.
Body: {account_id, from, to}
POST /api/files/chmod
Change file permissions (clamped to 0777 max).
Body: {account_id, path, mode} (e.g. "mode": "0755")
POST /api/files/upload
Upload a file. Multipart form data: account_id, path, file.
cron
GET /api/cron/list?account_id=<id>
List cron jobs for an account.
POST /api/cron/save
Create or update a cron job.
Body: {account_id, id?, schedule, command, enabled}
DELETE /api/cron/delete
Delete a cron job.
Body: {id}
packages
GET /api/packages/list
List all hosting packages.
Access: Admin, Reseller
POST /api/packages/create
Create a package.
Body:
{
"name": "Starter",
"disk_mb": 5120,
"max_email": 10,
"max_databases": 5,
"max_ftp": 5,
"max_domains": 10,
"max_subdomains": 20
}
POST /api/packages/update
Update a package.
Body: {id, ...same fields as create}
DELETE /api/packages/delete
Delete a package (accounts using it are unaffected).
Body: {id}
stats
GET /api/stats/account?account_id=<id>
Return usage stats for an account. For user role, account_id is inferred automatically.
GET /api/stats/server
Return historical server stats (CPU, RAM, disk) from the last 24 hours. Populated by the collect-stats.php cron every 5 minutes.
Access: Admin only
sessions
GET /api/sessions/list
List all active sessions (admin sees all, users see their own).
DELETE /api/sessions/revoke
Revoke a specific session.
Body: {session_id}
Access: Admin
DELETE /api/sessions/revoke-user
Revoke all sessions for a specific user.
Body: {user_id}
Access: Admin
DELETE /api/sessions/revoke-all
Revoke all active sessions on the panel.
Access: Admin
system
All system actions require Admin unless noted.
GET /api/system/version
Return panel version, git commit, PHP version, OS. No auth required.
GET /api/system/stats
Return live CPU, RAM, disk, uptime, and service status.
GET /api/system/check-update
Check GitHub for newer NovaCPX commits.
POST /api/system/apply-update
Pull the latest code and trigger a deploy.
GET /api/system/check-os-update
List available apt package upgrades.
POST /api/system/apply-os-update
Run apt-get upgrade and restart any services that went down.
GET /api/system/audit-log
Query the audit log.
Query params: page, per_page, user, action, date_from, date_to
GET /api/system/server-options
Return current web/mail/FTP/DNS server selections and detection state.
POST /api/system/save-option
Save a server option.
Body: {key, value} — allowed keys: web_server, mail_server, ftp_server, dns_server, whmcs_api_key, whmcs_enabled, ns1_hostname, ns2_hostname
GET /api/system/notify-settings
Return notification settings (API key masked).
POST /api/system/save-notify-settings
Save notification settings.
Body: {cybermail_api_key?, notify_from_email?, notify_from_name?, notify_admin_email?, notifications_enabled?}
POST /api/system/test-notify
Send a test email.
Body: {to}
POST /api/system/service-action
Start, stop, or restart a system service.
Body: {service, action} — action: start, stop, restart
branding
GET /api/branding/get
Return the branding settings for the current reseller.
Access: Reseller (own branding), Admin (pass reseller_id param)
POST /api/branding/save
Save branding settings.
Body: {panel_name?, primary_color?, accent_color?, support_email?, support_url?, hide_powered_by?, custom_css?}
POST /api/branding/upload-logo
Upload a logo image. Multipart: logo file field.
Accepts PNG, JPG, SVG, WEBP (max 512 KB).
POST /api/branding/delete-logo
Remove the current logo and revert to the default SVG.
whmcs
WHMCS billing bridge. Authenticate with X-WHMCS-Key: <key> header (configured in Server Options).
POST /api/whmcs/create
Provision a new hosting account.
Body: {domain, username, password, email, package_id?}
POST /api/whmcs/suspend
Suspend an account by domain.
Body: {domain, reason?}
POST /api/whmcs/unsuspend
Unsuspend an account by domain.
Body: {domain}
POST /api/whmcs/terminate
Terminate an account by domain.
Body: {domain}
POST /api/whmcs/changepackage
Switch an account to a different package.
Body: {domain, package_id}
GET /api/whmcs/info?domain=<domain>
Return account details for a domain.
docker
GET /api/docker/status
Engine status and container/image counts.
GET /api/docker/containers?account_id=<id>
List containers for an account (or all containers for admin with no account_id).
POST /api/docker/container-action
Body: {container_id, action} — action: start, stop, restart, remove
GET /api/docker/logs?container_id=<id>
Return the last 100 log lines from a container.
GET /api/docker/images
List pulled images.
POST /api/docker/pull
Pull an image.
Body: {image} e.g. "image": "nginx:latest"
POST /api/docker/run
Run a new container.
Body: {account_id, name, image, ports?, env?, volumes?}
Container names are namespaced as novacpx-<username>-<name>.
GET /api/docker/catalog
Return the one-click app catalog (9 apps: WordPress, Ghost, Nextcloud, Gitea, Matomo, Vaultwarden, Node.js, Flask, static).
POST /api/docker/launch-app
Deploy an app from the catalog.
Body: {account_id, app_id, ...app-specific config}
firewall
GET /api/firewall/rules
List UFW rules.
Access: Admin
POST /api/firewall/add-rule
Add a UFW rule.
Body: {port, protocol, action, from_ip?}
POST /api/firewall/delete-rule
Remove a rule by number.
Body: {rule_number}
GET /api/firewall/fail2ban
Return Fail2Ban jail status and banned IPs.
POST /api/firewall/unban
Unban an IP from a jail.
Body: {jail, ip}