Skip to content
NexPanel
Docs/Docs/API reference

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.