REST API
Where in the portal: API reference at
https://<your-domain>/apidoc(public) and API keys at/api-keys. Where in the admin: Customers › API keys (/customers/apikeys) lists the keys customers created.
What it does
Every action a customer can do in the portal — list and control VMs, read invoices, manage SSH keys, Kubernetes, storage, support tickets — is available through a versioned REST API under https://<your-domain>/v1/. Customers call it from scripts and CI with a scoped API key. The same API feeds the cmp command-line tool and the MCP server, and the reference is generated from the running installation, so it always lists exactly the features you have switched on.
Requirements
| Item | Requirement |
|---|---|
| Public HTTPS address | The API is served on your main domain (and on each reseller's own domain). |
| An API key | Created by the customer in the portal; see API keys. |
| Dependencies | None. Endpoints of a module you did not enable (for example Kubernetes or Object Storage) are hidden from the reference and refused. |
Prepare the infrastructure
Nothing to install. If a reverse proxy sits in front of NexCMP, forward /v1/, /mcp, /cli/ and /apidoc to the panel (the installer's nginx configuration already does).
Connect in NexCMP
The interactive reference
Open https://cloud.example.com/apidoc (replace the host with your domain; a reseller's customers see the reference on the reseller's domain, with the reseller's name). It has endpoint documentation with request and response examples in curl, the cmp CLI, JavaScript, Python and Go, a search box (Ctrl or Cmd + K), and a Try it panel. Try it sends requests to the same site only, with a key the visitor pastes (kept in the browser session); it is read-only by default, and write or paid calls need an extra switch and a confirmation.
Downloads and machine-readable documents
All are public, need no key and are generated per site:
| URL | Content |
|---|---|
/apidoc | Interactive reference. |
/v1/public/openapi.json | OpenAPI 3.1 document. |
/v1/public/openapi.yaml | Same, YAML. |
/v1/public/postman.json | Postman collection. |
/v1/public/insomnia.json | Insomnia export. |
/v1/public/api.md | The reference as one Markdown file. |
/v1/public/api-catalog | Light JSON: brand, base URL, key prefix, every scope and every endpoint with method, path, scope and whether it needs an Idempotency-Key. |
bash
curl -s https://cloud.example.com/v1/public/api-catalog | python3 -m json.tool | head -40
curl -sO https://cloud.example.com/v1/public/openapi.yamlIn Postman choose Import › Link and paste https://cloud.example.com/v1/public/postman.json. The reference page also offers one-file API clients for JavaScript and Python.
Authentication
Send the key in the Authorization header:
bash
curl -s https://cloud.example.com/v1/billing/wallet \
-H "Authorization: Bearer vk_XXXX"- Customer keys begin with
vk_. Keys are site-bound: a key created oncloud.example.comdoes not work on a reseller domain. - Browser session tokens (
pt_...) are for the portal only; use a key for automation. - The key's scopes decide what it may call; a missing scope answers HTTP 403
scope_required. See API keys. - Check a key with
GET /v1/apikeys/self: it returns the calling key's name, scopes, expiry and the remaining rate-limit allowance (every key may call it).
Examples
bash
# List virtual machines
curl -s "https://cloud.example.com/v1/vm?page=1" -H "Authorization: Bearer vk_XXXX"
# Start one (needs vm:write)
curl -s -X POST https://cloud.example.com/v1/vm/3f2a1c9e-0000-4000-8000-000000000000/start \
-H "Authorization: Bearer vk_XXXX"
# Create a VM (paid: needs vm:create and an Idempotency-Key)
curl -s -X POST https://cloud.example.com/v1/vm \
-H "Authorization: Bearer vk_XXXX" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d @vm.jsonTake the exact request fields of each operation from /apidoc.
Errors
Every error is JSON with a stable code and a human-readable message:
json
{"error": {"code": "scope_required", "message": "Key lacks scope vm:write"}}| HTTP | Typical code | Meaning |
|---|---|---|
| 401 | unauthenticated, key_invalid, key_revoked, key_expired, key_ip_denied, site_mismatch, api_keys_disabled | Missing or unknown key, revoked, expired, caller IP outside the key's allow list, a key from another site, or API keys switched off. |
| 403 | scope_required, endpoint_not_public, account_blocked, quota_exceeded, impersonate_forbidden | Key lacks the scope; the endpoint is not available to keys; the account is locked; a quota was reached; action not allowed in an impersonated session. |
| 404 | not_found | Not found — also returned for resources that belong to someone else. |
| 422 | invalid_argument | Validation error (field named in the response). |
| 429 | rate_limited | Too many requests; wait for Retry-After. |
| 503 | maintenance | Maintenance mode is on: reads work, writes are refused. |
Rate limits
| Limit | Default |
|---|---|
| Per key | 120 requests per minute |
| Per account (all keys together) | 300 requests per minute |
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 adds Retry-After.
Idempotency
Commands that cost money or cannot be repeated (create, change plan, buy, delete ...) require an Idempotency-Key header (any string up to 200 characters; a UUID works well). Send the same key again after a timeout and the server returns the original result (with Idempotency-Replayed: 1) instead of repeating the operation. Reusing a key for a different command answers 422; a request still in progress answers 409/Retry-After. Without the header a paid call is refused.
Verify
Create a key with scope
vm:readin the portal (API keys › Create key).Run:
bashcurl -i https://cloud.example.com/v1/apikeys/self -H "Authorization: Bearer vk_XXXX"You get HTTP 200 and the rate-limit headers.
curl -s https://cloud.example.com/v1/vm -H "Authorization: Bearer vk_XXXX"lists the account's VMs. In the portal the key's Last used column and the Key usage log show the calls.
Limits & notes
- Never available to a key: top-up, withdraw, change cards or auto top-up, change the password, e-mail or 2FA, delete the account, create, edit or revoke other keys. Those need a signed-in browser session.
- Hidden modules: the reference and the OpenAPI document only list features enabled on that site.
- Response size and paging: list endpoints are paged (
page,per_page); read the OpenAPI document for each endpoint. - Time and money: money is in USD cents unless the field name says otherwise.
- Admin API: the admin console has its own System › Admin › API page and administrator keys (
ofw_...) for administration; they are separate from the customer API described here. - Versioning: the path prefix
/v1is stable; new fields may be added to responses.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 401 on a new key | Key from another domain, expired, or typed with spaces | Create the key on the domain you call; check the Authorization: Bearer vk_... header. |
403 scope_required | Missing scope | Edit the key in the portal and add the scope. |
401 key_ip_denied or site_mismatch | Key restricted to other IPs ("allowed IPs") or created on another domain | Add your server's IP to the key's allowed IPs, or call the domain where the key was created. |
| 404 on an existing VM | The VM belongs to another account | Use a key of the owner. |
400/422 asking for Idempotency-Key | Paid operation without the header | Add Idempotency-Key: <uuid>. |
| 429 | Over the limit | Back off; use Retry-After. |
/apidoc shows less than expected | Module switched off | Enable the module in License & updates. |