Docs
API reference
NexPanel has one JSON API, version 1, on every panel port (admin :2087 and customer :2083):
https://panel.example.com:2087/api/v1/
Send the token in the Authorization header and ask for JSON:
curl -s https://panel.example.com:2087/api/v1/packages \
-H "Authorization: Bearer 3|Xr8e...token" -H "Accept: application/json"
Requests are limited to 120 a minute per token. Bodies are JSON (Content-Type: application/json) or form data.
Tokens
There are two kinds of token:
| Token | Made in | Reaches | Abilities |
|---|---|---|---|
| Staff token | Admin › Administration › API Tokens | every account: /api/v1/accounts/..., /packages, /usage, /nodes |
accounts:read, accounts:write, accounts:login, nodes:read |
| Customer token | Customer panel › Settings › API Tokens | only that account: /api/v1/account/... |
read only, or read and change |
- A staff token never works more than its owner's staff role allows: a Read-only staff member cannot change anything, even with
accounts:write. - Customer tokens stop working when the account is terminated, and can only read while it is suspended.
- Customers can set an expiry date on their tokens. Tokens are shown once; store them like a password.
Responses and errors
| Status | Meaning |
|---|---|
200 / 201 |
Done. Changes answer {"ok": true, "message": "..."}. |
202 |
Accepted: the server is still working on it ("pending": true, with a job_id). Staff can poll GET /jobs/{job_id}. |
401 |
Missing or wrong token. |
403 |
The token lacks the ability, belongs to the other kind, or the account is suspended (customer tokens). |
404 |
No such account, domain, mailbox, ... in this account. |
422 |
Not accepted: {"ok": false, "message": "...", "errors": {"field": ["..."]}}. Plan limits and validation use this. |
Changes made through the API go through the same checks as the panel (plan limits, reserved names, domain ownership) and are written to the audit log with the token's name.
Staff: accounts and packages
Base /api/v1. Ability in brackets.
| Method and path | What it does |
|---|---|
GET /packages (accounts:read) |
Packages and their limits. |
GET /nodes (nodes:read) |
Hosting servers: name, IP, accounts, PHP versions. |
GET /accounts (accounts:read) |
Accounts, 100 per page (?page=2, ?external_id=whmcs:123). |
POST /accounts (accounts:write) |
Create an account: domain, password, package (name or id); optional username, email, node, php_version, external_id. Answers 201 with the account and the job_id. |
GET /accounts/{username} (accounts:read) |
Account details, disk use, nameservers. |
POST /accounts/{username}/suspend (accounts:write) |
Suspend; optional reason. |
POST /accounts/{username}/unsuspend (accounts:write) |
Unsuspend. |
POST /accounts/{username}/password (accounts:write) |
New panel/SSH/FTP password: password. |
POST /accounts/{username}/package (accounts:write) |
Change package: package. |
POST /accounts/{username}/php (accounts:write) |
Default PHP version: php_version. |
DELETE /accounts/{username} (accounts:write) |
Terminate the account and delete its data. |
POST /accounts/{username}/login (accounts:login) |
One-click login link, see below. |
GET /usage (accounts:read) |
Disk use and limits of every account (?usernames=a,b). |
GET /jobs/{id} (accounts:read) |
Status of a background job. |
Staff tokens also reach everything in the next section under /api/v1/accounts/{username}/... (read with accounts:read, change with accounts:write).
Account: what a customer can do
Base /api/v1/account for customer tokens, or /api/v1/accounts/{username} for staff tokens.
| Method and path | What it does |
|---|---|
GET / |
The account: package, limits, usage, server IP, nameservers (customer tokens; staff use GET /accounts/{username}). |
POST /login |
One-click login link to the customer panel. |
GET /domains |
Domains, subdomains and aliases with SSL status. |
POST /domains |
Add a domain: type = addon, alias or subdomain; domain (or sub + parent for a subdomain); optional docroot. |
DELETE /domains/{domain} |
Remove an addon domain, subdomain or alias (files are kept). |
POST /domains/{domain}/ssl |
Request a free Let's Encrypt certificate. |
GET /dns |
DNS zones of the account. |
GET /dns/{zone} |
Records of a zone. |
POST /dns/{zone}/records |
Add a record: name, type, content, optional ttl, priority. |
DELETE /dns/{zone}/records |
Delete a record: name, type, content. |
GET /email/accounts |
Mailboxes with quota and use. |
POST /email/accounts |
New mailbox: email (or user + domain), password, optional quota_mb. |
PUT /email/accounts/{address} |
Change password, quota_mb, no_login, no_incoming, no_outgoing. |
DELETE /email/accounts/{address} |
Delete a mailbox and its mail. |
GET /email/forwarders |
Forwarders. |
POST /email/forwarders |
New forwarder: email, destinations (list or comma-separated). |
DELETE /email/forwarders/{id} |
Delete a forwarder. |
GET /databases |
Databases, database users and the name prefix. |
POST /databases |
New database: name (with or without the user_ prefix). |
DELETE /databases/{name} |
Delete a database. |
POST /databases/users |
New or changed database user: name, password. |
DELETE /databases/users/{name} |
Delete a database user. |
POST /databases/grant |
Give a user all privileges on a database: user, database (revoke: true to remove). |
GET /ftp · POST /ftp |
FTP accounts; new: name, password, optional dir, quota_mb. |
POST /ftp/{login}/password · DELETE /ftp/{login} |
Change the password of, or delete, an FTP account. |
GET /cron · POST /cron |
Cron jobs; new: schedule (5 fields), command. |
DELETE /cron/{id} |
Delete a cron job. |
GET /php · POST /php |
PHP versions; set the default with php_version (customer tokens). |
Single sign-on
POST .../login answers a link that logs the user in to the customer panel:
{"url": "https://panel.example.com:2083/panel/sso/kT3...", "expires_in": 60}
The link works once, for 60 seconds. Add "page" to open a section directly: dashboard, email, files, databases, domains, dns, ssl, backups, wordpress, ftp, cron, php, resources, visitors, settings. Billing systems use it for their "Log in to control panel" buttons. The login skips the customer's two-factor prompt (the billing system already signed the customer in), so only give accounts:login to systems you trust.
Examples
Create an account and log in to it:
T="Authorization: Bearer $NEXPANEL_TOKEN"; API=https://panel.example.com:2087/api/v1
curl -s -X POST $API/accounts -H "$T" -H "Accept: application/json" -H "Content-Type: application/json" \
-d '{"domain":"shop.example.com","password":"S3cure-Pass-2026","package":"Starter","email":"owner@example.com"}'
curl -s -X POST $API/accounts/shopexam/login -H "$T" -H "Accept: application/json" -d page=email
A customer adds a mailbox with their own token:
curl -s -X POST https://panel.example.com:2083/api/v1/account/email/accounts \
-H "Authorization: Bearer $MY_TOKEN" -H "Accept: application/json" \
-d email=info@shop.example.com -d password='Mail-Pass-2026' -d quota_mb=2048
Wrong or missing something? Let us know.