API guide

Get started with the AtlasNodes API: authentication, request rules and copy-paste examples.

Base URL

Every endpoint uses HTTPS and JSON (UTF-8) under the base URL below. The API version is part of the path (v1); incompatible changes will ship under a new version.

url
https://app.atlasnodes.com/api/v1

Every response carries an X-Request-Id header. Include its value when you contact support.

Authentication

Send the API key in the Authorization header with the Bearer scheme. Keys start with cvps_live_ and are shown only once when created — keep them in a secret manager, never in a repository.

shell
curl -s "$CLOUDVPS_API/regions" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY"

An invalid, expired or revoked key → 401 unauthenticated. API keys only work on Customer API endpoints (catalog, wallet, billing, SSH keys, servers, invoices, account limits); other panel endpoints (account, sessions, API keys) → 403 forbidden.

Creating an API key

  1. Open API Keys → Create API key and give it a name that says who uses it (e.g. "terraform-prod").
  2. Expiry (optional, at most 2 years): the key is rejected after that date.
  3. Access: Full for automation that creates or changes VPS, or Read-only for monitoring and reporting. Read-only keys may only use GET (and cannot retrieve root passwords); other requests → 403 api_key_read_only.
  4. Restrict IPs (optional): one IPv4/IPv6 address or CIDR per line, up to 20 (e.g. 203.0.113.10, 198.51.100.0/24, 2001:db8::/48). Empty = any IP. Requests from other IPs → 403 api_key_ip_not_allowed; details.ip holds your IP as seen by AtlasNodes — the list itself is never returned.
  5. Confirm with your account password (and 2FA code when enabled). The name, access level and IP list can be changed at any time with Edit; changes apply to the next request. Up to 10 active keys per account.

The account owner is notified when a key is used from an IP outside its list (at most once per hour per key).

Rate limits

The quota is counted per API key over a sliding 60-second window (60 requests/minute by default; the actual value is in X-RateLimit-Limit). Requests rejected because the endpoint is panel-only or the key is read-only count too; IP allowlist rejections are counted per caller IP, not per key.

X-RateLimit-Limit
Quota per minute.
X-RateLimit-Remaining
Quota left in the current window.
X-RateLimit-Reset
Time (epoch seconds) when one quota slot becomes available again.

When the quota runs out: 429 rate_limited with a Retry-After header and error.details.retry_after (seconds). Wait that long before retrying; use exponential backoff for other retries. Separately from the key quota, more than 30 failed authentications per minute from one IP (invalid key, suspended account, or IP outside the list; IPv6 counted per /64) also get 429 rate_limited with Retry-After, without X-RateLimit-* headers.

http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1791181212

{"error":{"code":"rate_limited","message":"Too many requests. Try again later.","details":{"retry_after":12},"request_id":"0b7c9d2e4f614a3b8c5d6e7f8a9b0c1d"}}

Idempotency-Key

Requests that create resources or charge your balance MUST send an Idempotency-Key header (missing → 428 idempotency_key_required):

  • POST /servers
  • POST /servers/{id}/reinstall
  • POST /servers/{id}/reset-password
  • POST /servers/{id}/resize
  • POST /servers/{id}/ip-addons
  • POST /servers/{id}/volumes
  • PATCH /servers/{id}/volumes/{volumeId}
  • POST /invoices/{id}/pay

Other mutating requests (POST/DELETE) may send it; the same rules apply when they do.

  • Use a unique value per operation (UUID v4 recommended), 1–255 ASCII characters without spaces. A key is valid for 24 hours per account and endpoint.
  • Retrying with the same key AND body returns the stored response (same status, Idempotent-Replayed: true header) without creating a second VPS or charging twice.
  • The same key with a different body → 422 idempotency_key_mismatch. The first request still running → 409 idempotency_in_progress (retry a few seconds later).
  • Error responses are not stored: after an error (e.g. 422 insufficient_balance) you may retry with the same key once you have fixed the cause.

Error format

All errors share one format. code is stable (English) — use it in program logic; message follows the Accept-Language: id or en header. request_id equals the X-Request-Id header.

json
{
  "error": {
    "code": "api_key_ip_not_allowed",
    "message": "Your IP address is not allowed to use this API key.",
    "details": { "ip": "203.0.113.7" },
    "request_id": "0b7c9d2e4f614a3b8c5d6e7f8a9b0c1d"
  }
}
StatusCodeMeaning
400validation_errorInvalid body/query; per-field details in details.fields.
401unauthenticatedThe API key is missing, invalid, expired or revoked.
403forbiddenThe endpoint cannot be used with an API key (panel only).
403account_suspendedThe account is suspended.
403email_not_verifiedVerify your email address before creating a VPS.
403server_suspendedThe VPS is suspended (e.g. an unpaid invoice).
403api_key_ip_not_allowedThe caller IP is not on this key’s IP list (details.ip).
403api_key_read_onlyA read-only key was used for a non-GET request.
404not_foundThe resource does not exist or is not yours.
409server_busyAnother action is still running for this VPS.
409invalid_stateThe action is not allowed in the VPS’s current state.
409price_changedThe price changed since you saw it; fetch the latest price and resend.
409idempotency_in_progressSee the Idempotency-Key section.
422insufficient_balanceInsufficient balance (details.required, details.available).
422limit_exceededAn account limit was reached (e.g. number of VPS).
422out_of_stockThe plan is out of stock in that region — check GET /catalog/availability and choose another region/plan.
422plan_unavailable · region_unavailable · image_unavailableThe plan, region or image is not available.
422idempotency_key_mismatchSee the Idempotency-Key section.
428idempotency_key_requiredSee the Idempotency-Key section.
429rate_limitedQuota exhausted; wait Retry-After seconds.
503upstream_unavailableThe VPS infrastructure is temporarily unreachable; try again later.

Money

Amounts are always 2-decimal strings with a currency (e.g. "6.00" + "USD"), never numbers. Hourly rates use 4–6 decimals (e.g. "0.0090"). Store and compute them as decimals, not floats.

Pagination

These list endpoints accept page (from 1) and per_page (default 20, max 100) and return meta:

  • GET /servers
  • GET /servers/{id}/actions
  • GET /servers/{id}/resizes
  • GET /wallet/transactions
  • GET /invoices
shell
curl -s "$CLOUDVPS_API/servers?page=2&per_page=50&status=running" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY"

# { "data": [ ... ], "meta": { "page": 2, "per_page": 50, "total": 73, "total_pages": 2 } }

Catalog lists (/regions, /tiers, /plans, /images) and /ssh-keys are returned in full without meta.

Asynchronous actions

Creating a VPS, power actions, reinstall, resize, root password reset and delete run in the background: the 202 response contains an action object with status pending. Poll that action every 3–5 seconds until its status is completed, failed or cancelled.

A VPS runs one action at a time; a new action while another is running → 409 server_busy. The server’s pending_action_id field shows the running action.

curl examples

The examples use the shell variables below. Replace IDs with values from earlier responses.

shell
export CLOUDVPS_API="https://app.atlasnodes.com/api/v1"
export CLOUDVPS_API_KEY="cvps_live_..."   # dari halaman API Keys / from the API Keys page

Catalog: regions, server tiers, plans and OS images

shell
curl -s "$CLOUDVPS_API/regions" -H "Authorization: Bearer $CLOUDVPS_API_KEY"
curl -s "$CLOUDVPS_API/tiers"   -H "Authorization: Bearer $CLOUDVPS_API_KEY"
curl -s "$CLOUDVPS_API/plans"   -H "Authorization: Bearer $CLOUDVPS_API_KEY"
curl -s "$CLOUDVPS_API/images?region_id=REGION_ID" -H "Authorization: Bearer $CLOUDVPS_API_KEY"
curl -s "$CLOUDVPS_API/catalog/availability" -H "Authorization: Bearer $CLOUDVPS_API_KEY"

/images?region_id= only lists operating systems available in that region. /catalog/availability shows stock per region & plan (available; remaining only when a stock limit is set).

Create a VPS (Idempotency-Key required)

shell
curl -s -X POST "$CLOUDVPS_API/servers" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "hostname": "web-production",
    "region_id": "REGION_ID",
    "plan_id": "PLAN_ID",
    "image_id": "IMAGE_ID",
    "ssh_key_ids": ["SSH_KEY_ID"]
  }'

The 202 response contains data.server (status pending) and data.action. ssh_key_ids is optional (at most 1, from GET /ssh-keys). Keep the same Idempotency-Key if you need to retry this request.

Poll the action until it finishes

shell
# SERVER_ID = data.server.id, ACTION_ID = data.action.id
while true; do
  STATUS=$(curl -s "$CLOUDVPS_API/servers/SERVER_ID/actions/ACTION_ID" \
    -H "Authorization: Bearer $CLOUDVPS_API_KEY" | jq -r '.data.status')
  echo "$STATUS"
  case "$STATUS" in completed|failed|cancelled) break ;; esac
  sleep 5
done

Retrieve the root password (once)

shell
curl -s "$CLOUDVPS_API/servers/SERVER_ID/initial-credentials" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY"

# { "data": { "username": "root", "password": "...", "expires_at": "..." } }

Available after the create/reinstall action completes and can be retrieved only once within 60 minutes. Requires a full-access key.

Console link (noVNC)

shell
curl -s -X POST "$CLOUDVPS_API/servers/SERVER_ID/console-link" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY"

# { "data": { "url": "https://…/console-link#…", "expires_at": "..." } }
# Buka data.url di tab baru dalam 60 detik (sekali pakai).

A console page link for a running VPS, valid for 60 seconds and single-use — suitable for handing to reseller customers. Open it in a new tab (cannot be iframed). Requires a full-access key.

Power actions

shell
# start | shutdown | stop | restart
curl -s -X POST "$CLOUDVPS_API/servers/SERVER_ID/restart" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY"

start powers on, shutdown shuts down gracefully (ACPI), stop forces power off, restart restarts. Empty body.

Reinstall the OS

shell
curl -s "$CLOUDVPS_API/servers/SERVER_ID/images" -H "Authorization: Bearer $CLOUDVPS_API_KEY"

curl -s -X POST "$CLOUDVPS_API/servers/SERVER_ID/reinstall" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "image_id": "IMAGE_ID" }'

image_id must be one of GET /servers/{id}/images. All data on the disk is erased.

Change the plan (resize)

shell
curl -s "$CLOUDVPS_API/servers/SERVER_ID/resize-options" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY"

curl -s -X POST "$CLOUDVPS_API/servers/SERVER_ID/resize" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "plan_id": "TARGET_PLAN_ID",
    "expected_price_hourly": "0.0179",
    "expected_monthly_cap": "12.00",
    "accept_downtime": true
  }'

Only for VPS on hourly billing. Take the target plan’s price_hourly and monthly_cap from resize-options and send them as expected_price_hourly / expected_monthly_cap with accept_downtime: true. Disks are never shrunk.

Delete a VPS

shell
curl -s -X DELETE "$CLOUDVPS_API/servers/SERVER_ID" \
  -H "Authorization: Bearer $CLOUDVPS_API_KEY"

202 response with a delete action. Deletion is permanent, including backups.

Wallet balance

shell
curl -s "$CLOUDVPS_API/wallet" -H "Authorization: Bearer $CLOUDVPS_API_KEY"

# { "data": { "currency": "USD", "balance": "20.00", "available_balance": "20.00", ... } }

balance, available_balance and other amounts are decimal strings in currency.

Full reference

Every endpoint, parameter, response schema and per-endpoint error code is in the interactive reference. The machine-readable spec (OpenAPI 3) can be used to generate client SDKs.