API overview
Everything the panel does goes through the same REST API, so a billing panel, a script or your own tools can do it too. Every permission is checked on every call, whether it comes from the panel or a token.
Base URL
https://panel.example.com/api/v1
Requests and responses are JSON. Request bodies must be sent as Content-Type: application/json, up to 1 MB.
curl https://panel.example.com/api/v1/servers \
-H "Authorization: Bearer pnl_…"
See Authentication and tokens for getting a token.
Who can call what
The same API serves three kinds of account. Each sees only what it owns:
| Account | Sees |
|---|---|
| Customer | Their own servers, and servers shared with them through team access |
| Reseller | Their own servers and their customers’ |
| Staff | Everything their role allows |
Another account’s server answers 404, never 403, so IDs can’t be probed.
The panel also has a built-in API reference: /api-reference for customers and resellers, and /admin/api/reference for staff. It lists every call the person can use, with its parameters, a TypeScript signature and a ready-to-copy curl command. It’s generated from the API client, so it can’t drift from the real API.
Successful responses
200with a JSON body, or204with no body.- Long-running actions (create, power, reinstall, move…) answer straight away with a job. Follow it with
GET /jobs/{jobId}until itsstateissucceededorfailed.
{ "jobId": "job_…", "serverId": "srv_abc123", "ipv4": "203.0.113.10" }
Errors
Errors have one shape:
{
"error": {
"code": "missing_scope",
"message": "This token needs one of these permissions: servers:power.",
"details": { "scopes": ["servers:power"] }
}
}
details is only there when it has something in it. Every response carries an X-Request-Id header; quote it when reporting a problem.
| Status | Codes |
|---|---|
| 400 | invalid_json, invalid_request, invalid_idempotency_key |
| 401 | invalid_token, not_authenticated |
| 403 | forbidden, missing_scope, scope_not_allowed, token_not_allowed, ip_not_allowed, csrf_failed, bad_origin, support_session |
| 404 | not_found, server_not_found, customer_not_found, … |
| 405 | method_not_allowed |
| 409 | hostname_taken, no_capacity, no_addresses, location_closed, account_locked, name_taken, email_taken, external_id_taken, reseller_suspended, quota_exceeded, snapshot_limit |
| 413 | too_large |
| 415 | unsupported_media_type |
| 422 | validation_failed, limit_reached, disk_too_small |
| 429 | rate_limited |
| 500 | internal_error |
| 503 | restarting |
Idempotency
Send an Idempotency-Key header (1–200 characters) on every POST, and reuse it when you retry. If the first request succeeded, the retry gets the same answer instead of doing the work twice, for 24 hours.
curl -X POST https://panel.example.com/api/v1/admin/servers \
-H "Authorization: Bearer pnl_…" \
-H "Idempotency-Key: order-10482" \
-H "Content-Type: application/json" \
-d '{ … }'
- Use a new key for each distinct operation, for example the order or invoice number. Keys are remembered per account and per endpoint, and the stored answer is returned without comparing request bodies.
- Failed requests aren’t remembered, so they can be retried with the same key.
- It’s honoured by the calls that create or change something you wouldn’t want twice: creating servers and customers, power, reinstall, snapshots, backups and restores, rescue, password resets, package changes, addresses, terminate, moves and imports.
Rate limits
| What | Limit |
|---|---|
| API calls | 1200 a minute, per token (or per account, or per address) |
| Sign-in calls | 20 a minute per address |
Over the limit, the API answers 429 rate_limited with a Retry-After header in seconds. While the controller restarts, changes get 503 restarting with Retry-After: 60; reads keep working.
Pagination
Lists that can be long return a page:
{ "data": [ … ], "nextCursor": "NTA=", "total": 312 }
Pass cursor (the previous page’s nextCursor) and limit. nextCursor is null on the last page. Cursors are opaque.
| List | Default | Max |
|---|---|---|
| Servers (staff) | 50 | 100 |
| Customers, reseller customers, transfers | 50 | 200 |
| IP pool addresses | 64 | 256 |
| Audit log | 50 | 1000 |
| Webhook deliveries | 25 | 100 |