Provisioning API

Updated 19 Oct 2026 Published

Provisioning API

The Provisioning API lets a billing system (ClientExec, WHMCS, Blesta, or your own) run the whole life of a hosting account on VinzaPanel: create it after an order, suspend it when an invoice is overdue, unsuspend it after payment, change its package, reset its password and terminate it at the end. It is the same API the VinzaPanel module for ClientExec uses (download below).

Every call is plain HTTPS + JSON, authenticated with a bearer token. All paths below are relative to your panel: https://<your-panel>/api/v1/provisioning/ (for a default install that is https://panel.example.com:2711/api/v1/provisioning/). The interactive OpenAPI reference of your own panel is at /api/v1/docs (administrators only).

Requirements

  • VinzaPanel 1.3.40 or newer (login_url in responses: 1.3.43).
  • A licence whose plan allows the number of hosting accounts you sell — the Free plan allows only the administrator account.
  • For several servers: the nodes connected to the panel (Servers); each account can be placed on the node you choose.

Authentication

Create a dedicated token in the panel: Profile → API tokens → New token, scope “Provisioning only”, and put your billing server's IP address in Allowed IPs. Create it from an administrator account protected with two-factor authentication. The secret is shown once.

Authorization: Bearer vzp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

A provisioning-scoped token can only reach /api/v1/provisioning/; any other endpoint answers 403, and so does a call from an address outside the allow-list.

Endpoints

MethodPathPurpose
GETplans/Hosting plans (limits, features) and the servers accounts can be placed on
GETaccounts/?search=&limit=&offset=List hosting accounts (max 500 per page)
POSTaccounts/Create an account, optionally with its first website → 201
GETaccounts/{username}/Account details: status, plan, server, websites, disk/database/domain usage
POSTaccounts/{username}/suspend/Suspend ({"reason": "…"}): websites answer 503, logins are refused, mail keeps arriving
POSTaccounts/{username}/unsuspend/Undo the suspension exactly
POSTaccounts/{username}/password/Set the password ({"password": "…"}) — panel login and the account's system user
POSTaccounts/{username}/plan/Change the package ({"plan": "Business"}, id or name; null = no plan)
POSTaccounts/{username}/terminate/Terminate ({"skip_backup": false}) → 202 with a poll URL; a final backup is kept 30 days
GETterminations/{id}/Termination progress: queued / running / done / failed
POSTaccounts/{username}/move/Move the account to another server ({"server": "node-sg-1"}, id or name; null = panel host) → 202 with a poll URL
GETmoves/{id}/Move progress: queued / running / done / failed

Create an account

POST /api/v1/provisioning/accounts/
Authorization: Bearer vzp_…
Idempotency-Key: order-1001
Content-Type: application/json

{
  "username": "alice",
  "password": "S3cure-pass!2026",
  "email": "[email protected]",
  "first_name": "Alice",
  "plan": "Business",
  "server": "node-sg-1",
  "domain": "alice.example",
  "php_version": "8.3"
}

plan and server accept an id or a name (see plans/); omit server to use the panel's own host. With domain the first website is created too; if that fails, the account is rolled back and the call answers 400, so a retry starts clean.

HTTP/1.1 201 Created

{
  "success": true,
  "account": {
    "id": "8c1e…",
    "username": "alice",
    "email": "[email protected]",
    "status": "active",
    "plan": {"id": "2", "name": "Business", "is_default": false,
             "limits": {"websites": 5, "databases": 5, "disk_mb": 5120, "…": "…"},
             "features": {"ssl": true, "ftp": true, "git": false, "ssh": false}},
    "server": "node-sg-1",
    "login_url": "https://panel.example.com:2711/login/",
    "linux_user": "alice",
    "websites": ["alice.example"],
    "usage": {"disk_used_mb": 0, "disk_quota_mb": 5120, "websites": 1, "databases": 0, "domains": 1}
  }
}

Put login_url, the username and the password in your welcome email. Account status is one of active, suspended, terminating or disabled.

Retries and idempotency

Billing systems retry after timeouts. Send an Idempotency-Key header (the order or invoice number) with every POST:

  • Same key, same body → the first successful answer is returned again with "idempotent_replay": true; nothing is created twice.
  • Same key, different body → 409.
  • Same key while the first request is still running → 409 “still in progress”; retry shortly.
  • Failed answers are not kept, so a retry after a temporary error really runs again. Keys are kept for one day. Passwords are never stored.

Terminating

POST /api/v1/provisioning/accounts/alice/terminate/
{"skip_backup": false}

HTTP/1.1 202 Accepted
{"success": true, "termination": {"id": 7, "status": "queued", …},
 "poll": "/api/v1/provisioning/terminations/7/"}

Termination runs in the background: the account is suspended, a final backup of its files, databases and mail is taken (kept 30 days on the server), then its websites, databases, mail, FTP accounts, cron jobs and system user are removed. Poll the poll URL until status is done; a failed job lists its errors and can be retried from the panel without losing what was already done.

Errors

Errors are JSON: {"success": false, "error": "…"}.

HTTPMeaning
400Invalid input (username taken, plan or server not found, weak password, website could not be created)
401Missing or invalid token
403Token not allowed here (scope or IP allow-list), or the target is an administrator account
404No such hosting account
409Idempotency-Key reused with another body, or the first request is still running

ClientExec module

Download the VinzaPanel server plugin for ClientExec (v1.0.0)

  1. Unzip and copy plugins/server/vinzapanel/ into your ClientExec installation, so that the file ends up at <clientexec>/plugins/server/vinzapanel/PluginVinzapanel.php.
  2. In VinzaPanel create a token with the Provisioning only scope and your ClientExec server's IP in Allowed IPs (see Authentication above).
  3. In ClientExec: Settings → Products → Servers → Add Server, plugin VinzaPanel; enter the panel hostname, the API token and the panel port (2711 by default), then press Test Connection.
  4. For each hosting product set Package Name On Server to the VinzaPanel plan (name or id). Optional package settings: Node (which VinzaPanel server the account goes on) and PHP Version.

Create, Suspend, UnSuspend, Delete (terminate with a final backup), password changes, upgrades/downgrades and the client-area login link are supported. Retries are safe: Create does nothing when the account already exists.

Mapping for billing systems

Billing actionCall
Create / activatePOST accounts/
Suspend (overdue)POST accounts/{username}/suspend/
Unsuspend (paid)POST accounts/{username}/unsuspend/
Upgrade / downgradePOST accounts/{username}/plan/
Change passwordPOST accounts/{username}/password/
Terminate / cancelPOST accounts/{username}/terminate/ then poll
Test connectionGET plans/

Resources (websites, databases, mail and FTP accounts, cron jobs, disk, PHP workers) follow the account's plan; to change them for one customer, move that customer to another plan.

Moving accounts between servers

The server field on create only chooses where a new account starts. To move an existing account later, call POST accounts/{username}/move/ with the target server (id or name, null for the panel host) and poll the returned moves/{id}/ URL until status is done. The move copies the account's home, websites, databases, certificates, crontab and FTP accounts; its websites are offline (suspended) while they are copied, mail stays on the panel host, and the old copy is removed after 7 days. A request the target cannot take (missing PHP version, no MySQL/MariaDB, not enough disk, unconfirmed node…) is refused with 400 and the reason. The same move is available in the panel as Move to another server on the account's edit page (Server → Users); see the Vinza Server page.

On this page