NexNodeReseller API v1.1.0

شروع سریع

از صفر تا یک سرور

از کلید API تا یک سرور آماده، با پنج درخواست. در نمونه‌ها کلید از متغیر NEXNODE_TOKEN خوانده می‌شود.

نشانی پایه https://api.nexnode.cloud/api/v1 https://api.nexnode.ir/api/v1داخل ایران
  1. 1انتخاب پلن
  2. 2بررسی قیمت
  3. 3ثبت سفارش
  4. 4منتظر ساخت بمانید
  5. 5اتصال

مرحله 1/5

انتخاب پلن

فهرست پلن‌هایی را که می‌توانید سفارش بدهید بگیرید. با country_code یا datacenter_id می‌توانید فهرست را محدود کنید و با lang=en نام‌ها را انگلیسی بگیرید.

از پلنی که انتخاب می‌کنید این‌ها را لازم دارید: id خود پلن، id یکی از templates که همان سیستم‌عامل است، و id امکاناتی از features که می‌خواهید.

curl -G "https://api.nexnode.cloud/api/v1/catalog/servers" \
  -d country_code=DE \
  -d lang=en \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os
import requests

BASE = "https://api.nexnode.cloud/api/v1"
api = requests.Session()
api.headers["X-API-Token"] = os.environ["NEXNODE_TOKEN"]

params = {"country_code": "DE", "lang": "en"}
response = api.get(f"{BASE}/catalog/servers", params=params)
plan = response.json()["data"][0]
<?php

const BASE = 'https://api.nexnode.cloud/api/v1';

function nexnode(
    string $method,
    string $path,
    ?array $body = null,
    array $headers = [],
): array {
    $options = [
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_RETURNTRANSFER => true,
    ];
    $headers[] = 'X-API-Token: ' . getenv('NEXNODE_TOKEN');
    if ($body !== null) {
        $headers[] = 'Content-Type: application/json';
        $options[CURLOPT_POSTFIELDS] = json_encode($body);
    }
    $options[CURLOPT_HTTPHEADER] = $headers;
    $ch = curl_init(BASE . $path);
    curl_setopt_array($ch, $options);
    return json_decode(curl_exec($ch), true);
}

$query = http_build_query(['country_code' => 'DE', 'lang' => 'en']);
$plan = nexnode('GET', "/catalog/servers?$query")['data'][0];
پاسخ
{
  "success": true,
  "data": [
    {
      "id": 42,
      "name": "CX22",
      "cpu": 2,
      "memory": 4,
      "disk": 40,
      "location": {"id": 3, "name": "Falkenstein"},
      "prices": [
        {"term": "hourly", "price": 0.0097, "currency": "USD"}
      ],
      "templates": [
        {"id": 7, "name": "Ubuntu 24.04", "os_type": "linux"}
      ],
      "features": [
        {"id": 12, "name": "Backups", "price": 0.0015}
      ]
    }
  ]
}

مرحله 2/5

بررسی قیمت

پیش از سفارش، همان انتخاب را به POST /quote بفرستید. cost مبلغ اولین برداشت است و sufficient_balance می‌گوید موجودی کیف‌پول کافی است یا نه. اگر کافی نباشد، difference کسری را نشان می‌دهد.

مبلغ سفارش‌هایی که هنوز در حال ساخت‌اند کنار گذاشته می‌شود و در reserved می‌آید؛ پس برای دو سفارش هم‌زمان باید موجودی هر دو را داشته باشید.

curl -X POST "https://api.nexnode.cloud/api/v1/quote" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "server_id": 42,
    "template_id": 7,
    "term": "hourly",
    "active_features": ["12"]
  }'
choice = {
    "server_id": plan["id"],
    "template_id": plan["templates"][0]["id"],
    "term": "hourly",
    "active_features": ["12"],
}
quote = api.post(f"{BASE}/quote", json=choice).json()["data"]
if not quote["sufficient_balance"]:
    raise SystemExit(f"Top up {quote['difference']} USD first")
$choice = [
    'server_id' => $plan['id'],
    'template_id' => $plan['templates'][0]['id'],
    'term' => 'hourly',
    'active_features' => ['12'],
];
$quote = nexnode('POST', '/quote', $choice)['data'];
if (!$quote['sufficient_balance']) {
    exit("Top up {$quote['difference']} USD first\n");
}
پاسخ
{
  "success": true,
  "data": {
    "server_id": 42,
    "term": "hourly",
    "active_features": ["12"],
    "cost": 0.0112,
    "creation_fee": 0.0,
    "recurring": 0.0112,
    "balance": 8.42,
    "reserved": 0.0,
    "sufficient_balance": true,
    "difference": 0.0
  }
}

مرحله 3/5

ثبت سفارش

POST /instances همان فیلدها را می‌گیرد. هدر Idempotency-Key را همیشه بفرستید: اگر اتصال قطع شد و درخواست را با همان کلید تکرار کردید، به‌جای سرور دوم، همان سفارش اول برمی‌گردد.

order_id را نگه دارید.

curl -X POST "https://api.nexnode.cloud/api/v1/instances" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Idempotency-Key: 5f0c7a52-3a1b-4c55-9d8e-2b7e4f1a9c03" \
  -H "Content-Type: application/json" \
  -d '{
    "server_id": 42,
    "template_id": 7,
    "term": "hourly",
    "active_features": ["12"]
  }'
import uuid

# Keep the key: a retry must send the same one.
key = str(uuid.uuid4())
headers = {"Idempotency-Key": key}
response = api.post(f"{BASE}/instances", json=choice, headers=headers)
order_id = response.json()["data"]["order_id"]
// Keep the key: a retry must send the same one.
$key = bin2hex(random_bytes(16));
$headers = ["Idempotency-Key: $key"];
$order = nexnode('POST', '/instances', $choice, $headers)['data'];
$orderId = $order['order_id'];
پاسخ
{
  "success": true,
  "data": {"order_id": 9001, "price": 0.0112, "apps": []},
  "meta": {
    "note": "Poll GET /orders/{order_id} until status leaves pending"
  }
}

مرحله 4/5

منتظر ساخت بمانید

ساخت سرور بسته به دیتاسنتر از چند ثانیه تا چند دقیقه طول می‌کشد. هر چند ثانیه یک‌بار GET /orders/{order_id} را صدا بزنید تا status دیگر pending نباشد، یا وب‌هوک ثبت کنید و منتظر رویداد order.deployed بمانید.

وقتی وضعیت deployed شد، server.id شناسه‌ی سرور شماست. سفارشی که به timed_out برسد، نه سروری می‌سازد و نه مبلغی کسر می‌کند.

curl "https://api.nexnode.cloud/api/v1/orders/9001" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import time

while True:
    status = api.get(f"{BASE}/orders/{order_id}").json()["data"]
    if status["status"] != "pending":
        break
    time.sleep(5)

if status["status"] != "deployed":
    raise SystemExit("The order timed out; nothing was charged")
instance_id = status["server"]["id"]
while (true) {
    $status = nexnode('GET', "/orders/$orderId")['data'];
    if ($status['status'] !== 'pending') {
        break;
    }
    sleep(5);
}

if ($status['status'] !== 'deployed') {
    exit("The order timed out; nothing was charged\n");
}
$instanceId = $status['server']['id'];
پاسخ
{
  "success": true,
  "data": {
    "order_id": 9001,
    "status": "deployed",
    "success": true,
    "created_at": "2026-09-16T10:00:00+00:00",
    "finished_at": "2026-09-16T10:01:12+00:00",
    "server": {
      "id": 123,
      "name": "Nex1-123",
      "status": "online",
      "ipv4": "203.0.113.7"
    }
  }
}
وب‌هوک
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "order.deployed",
  "created_at": "2026-09-16T10:01:12+00:00",
  "data": {
    "order_id": 9001,
    "status": "deployed",
    "instance_id": 123,
    "server_id": 42,
    "price": 0.0112
  }
}

مرحله 5/5

اتصال

GET /instances/{id} آدرس IP و اطلاعات ورود را برمی‌گرداند. تا وقتی دیتاسنتر رمز و IP را تحویل نداده، credentials.pending برابر true است؛ این ممکن است تا چند دقیقه بعد از تکمیل سفارش طول بکشد.

از این به بعد، روشن و خاموش کردن، ریبوت و نصب مجدد سیستم‌عامل با POST /instances/{id}/actions انجام می‌شود. DELETE /instances/{id} سرور را حذف می‌کند و هزینه‌اش هم قطع می‌شود.

curl "https://api.nexnode.cloud/api/v1/instances/123" \
  -H "X-API-Token: $NEXNODE_TOKEN"
server = api.get(f"{BASE}/instances/{instance_id}").json()["data"]
login = server["credentials"]
print(f"ssh -p {login['port']} {login['username']}@{login['ipv4']}")
$server = nexnode('GET', "/instances/$instanceId")['data'];
$login = $server['credentials'];
echo "ssh -p {$login['port']} {$login['username']}@{$login['ipv4']}\n";
پاسخ
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "ipv4": "203.0.113.7",
    "renewal_due": "2026-09-16T11:01:12+00:00",
    "credentials": {
      "username": "root",
      "password": "hX7kq2Lp9vQe",
      "port": 22,
      "ipv4": "203.0.113.7",
      "pending": false
    }
  }
}

مبانی

کلید API

کلید را پشتیبانی صادر می‌کند و فقط یک‌بار نشان داده می‌شود. ما فقط هش آن را نگه می‌داریم، پس کلید گم‌شده قابل بازیابی نیست. از پشتیبانی کلید تازه بخواهید؛ کلید قبلی همان لحظه باطل می‌شود.

کلید را در همه‌ی درخواست‌ها با یکی از این دو هدر بفرستید. فقط GET /health بدون کلید کار می‌کند، و GET /account چند حرف اول کلیدی را که استفاده می‌کنید نشان می‌دهد.

نشانی پایه https://api.nexnode.cloud/api/v1 است. اگر از داخل ایران به کلادفلر دسترسی خوبی ندارید، https://api.nexnode.ir/api/v1 را به کار ببرید؛ هر دو به همان API و همان حساب وصل‌اند.

هدرها
X-API-Token: sk_...
Authorization: Bearer sk_...

امتحان در مرورگر

کنار هر مسیر در مرجع یک دکمه‌ی Try it هست. درخواست با کلید خودتان از همین صفحه به API فرستاده می‌شود و پاسخ واقعی را می‌بینید.

کلید فقط در همین تب مرورگر می‌ماند و با بستن تب پاک می‌شود. درخواست‌های خواندنی بلافاصله فرستاده می‌شوند. هر کاری که هزینه دارد یا سرور را تغییر می‌دهد، اول از شما تأیید می‌گیرد؛ چون حالت آزمایشی وجود ندارد و سروری که از اینجا سفارش بدهید، سرور واقعی است و هزینه‌اش از کیف‌پولتان کسر می‌شود.

اگر با Postman یا Insomnia کار می‌کنید، سند OpenAPI را در آن ایمپورت کنید؛ همه‌ی مسیرها، فیلدها و نمونه‌ها همراهش می‌آیند.

ایمپورت در Postman یا Insomnia
https://api.nexnode.cloud/openapi.json

پاسخ‌ها و خطاها

همه‌ی پاسخ‌ها یک قالب دارند. در کدتان بر اساس error.code تصمیم بگیرید، نه error.message؛ متن پیام ممکن است عوض شود، اما کد ثابت می‌ماند.

هر پاسخ هدر X-Request-ID دارد. وقتی به پشتیبانی پیام می‌دهید، همین را بفرستید تا درخواست‌تان را پیدا کنیم.

خطایی که از سمت دیتاسنتر باشد (provider_error، deploy_rejected) یک error.reference هم دارد؛ کدی کوتاه مثل NX-7K3F2M. سفارشی که به timed_out برسد همین کد را به‌صورت reference روی خود سفارش و در وب‌هوک آن دارد. همین کد را ربات و پنل به مشتری شما نشان می‌دهند و با آن، خطا را در لاگ‌های ما یک‌راست پیدا می‌کنیم: آن را به مشتری بدهید و وقت پیگیری برای پشتیبانی بفرستید.

منبعی که مال حساب شما نباشد همیشه 404 برمی‌گرداند، نه 403؛ پس از پاسخ نمی‌شود فهمید آن شناسه اصلاً وجود دارد یا نه.

کد وضعیت یعنی
validation_error 400 ورودی نامعتبر است؛ message فیلد مشکل‌دار را می‌گوید
unauthorized 401 کلید ارسال نشده یا نادرست است
insufficient_balance 402 موجودی کافی نیست؛ مبلغ سفارش‌های در حال ساخت هم حساب می‌شود
forbidden 403 حساب مسدود است، دیتاسنتر برای شما بسته است یا احراز هویت لازم است
not_found 404 وجود ندارد یا مال شما نیست
instance_locked 409 سرور قفل است: بدهی، عبور از سقف ترافیک یا در حال حذف
rate_limited 429 بیش از حد مجاز درخواست فرستاده‌اید؛ Retry-After را ببینید
server_error 500 خطا از سمت ماست؛ request_id را برای پشتیبانی بفرستید
provider_error 502 دیتاسنتر جواب نداد؛ کمی بعد دوباره امتحان کنید و اگر تکرار شد error.reference را برای پشتیبانی بفرستید
پاسخ موفق
{"success": true, "data": {"id": 123}, "meta": {}}
پاسخ خطا
{
  "success": false,
  "error": {
    "code": "not_found",
    "message": "Instance not found",
    "request_id": "7c9e6679a1b2"
  }
}

جلوگیری از سفارش تکراری

اگر وسط POST /instances اتصال قطع شود، معلوم نیست سفارش ثبت شده یا نه، و تکرار درخواست ممکن است سرور دوم بخرد. برای همین هدر Idempotency-Key را با یک مقدار یکتا، مثلاً یک UUID، بفرستید.

تکرار درخواست با همان کلید و همان بدنه، سفارش اول را همراه با meta.idempotent_replay: true برمی‌گرداند و چیز تازه‌ای نمی‌سازد.

  • همان کلید با بدنه‌ی دیگر: 422 idempotency_key_reused
  • درخواست اول هنوز تمام نشده: 409 idempotency_in_progress
  • هر کلید 24 ساعت نگه داشته می‌شود.
  • درخواست ناموفق ثبت نمی‌شود؛ مثلاً بعد از شارژ کیف‌پول می‌توانید با همان کلید دوباره بفرستید.
سفارش تکراری
{
  "success": true,
  "data": {"order_id": 9001, "price": 0.0112, "apps": []},
  "meta": {"idempotent_replay": true}
}

فهرست‌ها و زبان

مسیرهای فهرستی همه‌ی موارد را یک‌جا برمی‌گردانند. برای صفحه‌بندی limit (از 1 تا 500) و در صورت نیاز offset را بفرستید؛ آن‌وقت meta.page هم در پاسخ می‌آید.

نام‌ها و توضیحات به‌طور پیش‌فرض فارسی‌اند. برای انگلیسی، lang=en یا هدر Accept-Language: en را بفرستید.

curl -G "https://api.nexnode.cloud/api/v1/instances" \
  -d limit=50 \
  -d offset=100 \
  -H "X-API-Token: $NEXNODE_TOKEN"
params = {"limit": 50, "offset": 100}
page = api.get(f"{BASE}/instances", params=params).json()
total = page["meta"]["page"]["total"]
$query = http_build_query(['limit' => 50, 'offset' => 100]);
$page = nexnode('GET', "/instances?$query");
$total = $page['meta']['page']['total'];
پاسخ
{
  "success": true,
  "data": [],
  "meta": {"page": {"total": 128, "limit": 50, "offset": 100}}
}

سقف درخواست

سقف‌ها برای هر کلید جدا حساب می‌شوند:

  • خواندن: 60 تا 120 درخواست در دقیقه برای هر مسیر
  • POST /instances: 10 درخواست در دقیقه
  • دستورهای سرور: 30 درخواست در دقیقه
  • تغییر وب‌هوک: 10 درخواست در دقیقه

اگر از سقف بگذرید، پاسخ 429 می‌گیرید و هدر Retry-After می‌گوید چند ثانیه صبر کنید.

پاسخ
HTTP/1.1 429 Too Many Requests
Retry-After: 18

{
  "success": false,
  "error": {"code": "rate_limited", "message": "Too many requests"}
}

وب‌هوک

به‌جای اینکه وضعیت را پشت سر هم چک کنید، یک آدرس HTTPS و یک رمز با PUT /account/webhook ثبت کنید تا رویدادها برایتان فرستاده شوند. هر رویداد یک درخواست POST با این هدرهاست:

  • X-Nexnode-Event: نام رویداد
  • X-Nexnode-Delivery: شناسه‌ی ارسال؛ در تلاش دوباره عوض نمی‌شود، پس با آن جلوی پردازش تکراری را بگیرید
  • X-Nexnode-Signature: امضا به شکل t=<unix seconds>,v1=<hex>

پیش از هر کاری امضا را بررسی کنید: v1 باید با HMAC_SHA256(secret, "<t>." + raw_body) یکی باشد و t بیشتر از چند دقیقه با زمان فعلی فاصله نداشته باشد. امضا روی بدنه‌ی خام حساب می‌شود، نه روی JSONِ دوباره ساخته‌شده.

تا 15 ثانیه یک پاسخ 2xx بدهید. اگر ندهید، ارسال بعد از 30 ثانیه و یک بار دیگر بعد از 5 دقیقه تکرار می‌شود و بعد دیگر فرستاده نمی‌شود. درخواست‌ها از رله‌ی ما می‌آیند، نه از نشانی API؛ به امضا تکیه کنید، نه به IP. فهرست رویدادها و بدنه‌ی هر کدام در بخش Webhooks مرجع آمده است.

import hashlib
import hmac
import time


def verify(secret: str, header: str, body: bytes,
           tolerance: int = 300) -> bool:
    fields = dict(part.split("=", 1) for part in header.split(","))
    ts, given = int(fields["t"]), fields["v1"]
    if abs(time.time() - ts) > tolerance:
        return False
    signed = f"{ts}.".encode() + body
    digest = hmac.new(secret.encode(), signed, hashlib.sha256)
    return hmac.compare_digest(given, digest.hexdigest())
<?php

function verify(
    string $secret,
    string $header,
    string $body,
    int $tolerance = 300,
): bool {
    $fields = [];
    foreach (explode(',', $header) as $part) {
        [$name, $value] = explode('=', $part, 2) + [1 => ''];
        $fields[$name] = $value;
    }
    $ts = (int) ($fields['t'] ?? 0);
    if (abs(time() - $ts) > $tolerance) {
        return false;
    }
    $expected = hash_hmac('sha256', "$ts.$body", $secret);
    return hash_equals($expected, $fields['v1'] ?? '');
}

// In your endpoint: the raw body, not a re-encoded array.
$body = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_NEXNODE_SIGNATURE'] ?? '';
if (!verify(getenv('NEXNODE_WEBHOOK_SECRET'), $header, $body)) {
    http_response_code(401);
    exit;
}
ثبت وب‌هوک
curl -X PUT "https://api.nexnode.cloud/api/v1/account/webhook" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/nexnode",
    "secret": "a-long-random-secret"
  }'

مرجع API

نام مسیرها، فیلدها و کدهای خطا را در کد عیناً همین‌طور می‌نویسید، برای همین این بخش انگلیسی است.

Catalogue

Plans, datacenters, locations and one-click apps this account may order, and the exact price of a configuration. Prices are hourly USD.

Server catalog

GET/catalog/servers

Every orderable plan with hourly prices, templates, features and the actions its instances support. Filter by datacenter_id and country_code.

Query parameters

  • lang string or null
    fa (default) or en for names and descriptions. Accept-Language is honoured too.
  • limit integer or null
    Page size (1-500). Omit for everything.
  • offset integer default 0
  • datacenter_id integer or null
  • country_code string or null
    ISO country code filter.
  • term string or null
    Only hourly is accepted.
Response fields 30

data[]

  • id integer required
  • name string required
  • type string required
  • cpu integer required
  • memory integer required
    GB
  • disk integer required
    GB
  • term_filter string required
    Billing term the prices and features are for. Only hourly is offered.
  • prices array of objects required
  • creation_fee number required
    One-time fee added to the first charge; 0 when none.
  • templates array of objects required
  • features array of objects required
  • actions array of strings required
    Provider actions instances of this plan support.
  • datacenter object or null
  • datacenter.id integer required
  • datacenter.name string required
  • datacenter.description string or null
  • datacenter.status string or null
  • datacenter.enabled boolean
  • datacenter.terms array of objects
    Enabled billing terms.
  • datacenter.require_kyc boolean
  • location object or null
  • location.id integer required
  • location.datacenter_id integer required
  • location.name string required
  • location.country string required
  • location.country_code string required
  • location.flag string or null
  • location.active boolean
  • location.status string or null
  • traffic object or null

Errors400401429

curl "https://api.nexnode.cloud/api/v1/catalog/servers" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/catalog/servers",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/catalog/servers');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": 123,
      "name": "Nex1-123",
      "type": "cloud",
      "cpu": 2,
      "memory": 4,
      "disk": 40,
      "term_filter": "hourly",
      "prices": [
        {}
      ],
      "creation_fee": 0.0112,
      "templates": [
        {}
      ],
      "features": [
        {}
      ],
      "actions": ["reboot"],
      "datacenter": {
        "id": 1,
        "name": "EU Central",
        "description": "Example DC",
        "status": "available",
        "enabled": true,
        "terms": [
          {}
        ],
        "require_kyc": false
      },
      "location": {
        "id": 3,
        "datacenter_id": 1,
        "name": "Nex1-123",
        "country": "Germany",
        "country_code": "DE",
        "flag": "🇩🇪",
        "active": true,
        "status": "online"
      },
      "traffic": {}
    }
  ]
}

One catalog server

GET/catalog/servers/{server_id}

Path parameters

  • server_id integer required

Query parameters

  • lang string or null
    fa (default) or en for names and descriptions. Accept-Language is honoured too.
Response fields 30

data

  • id integer required
  • name string required
  • type string required
  • cpu integer required
  • memory integer required
    GB
  • disk integer required
    GB
  • term_filter string required
    Billing term the prices and features are for. Only hourly is offered.
  • prices array of objects required
  • creation_fee number required
    One-time fee added to the first charge; 0 when none.
  • templates array of objects required
  • features array of objects required
  • actions array of strings required
    Provider actions instances of this plan support.
  • datacenter object or null
  • datacenter.id integer required
  • datacenter.name string required
  • datacenter.description string or null
  • datacenter.status string or null
  • datacenter.enabled boolean
  • datacenter.terms array of objects
    Enabled billing terms.
  • datacenter.require_kyc boolean
  • location object or null
  • location.id integer required
  • location.datacenter_id integer required
  • location.name string required
  • location.country string required
  • location.country_code string required
  • location.flag string or null
  • location.active boolean
  • location.status string or null
  • traffic object or null

Errors401404

curl "https://api.nexnode.cloud/api/v1/catalog/servers/42" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/catalog/servers/42",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/catalog/servers/42');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "type": "cloud",
    "cpu": 2,
    "memory": 4,
    "disk": 40,
    "term_filter": "hourly",
    "prices": [
      {}
    ],
    "creation_fee": 0.0112,
    "templates": [
      {}
    ],
    "features": [
      {}
    ],
    "actions": ["reboot"],
    "datacenter": {
      "id": 1,
      "name": "EU Central",
      "description": "Example DC",
      "status": "available",
      "enabled": true,
      "terms": [
        {}
      ],
      "require_kyc": false
    },
    "location": {
      "id": 3,
      "datacenter_id": 1,
      "name": "Nex1-123",
      "country": "Germany",
      "country_code": "DE",
      "flag": "🇩🇪",
      "active": true,
      "status": "online"
    },
    "traffic": {}
  }
}

List datacenters

GET/datacenters

Datacenters the account may order from (account restrictions applied). One whose status is not available takes no orders for now.

Query parameters

  • lang string or null
    fa (default) or en for names and descriptions. Accept-Language is honoured too.
Response fields 7

data[]

  • id integer required
  • name string required
  • description string or null
  • status string or null
  • enabled boolean
  • terms array of objects
    Enabled billing terms.
  • require_kyc boolean

Errors401429

curl "https://api.nexnode.cloud/api/v1/datacenters" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/datacenters",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/datacenters');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "EU Central",
      "description": "Example DC",
      "status": "available",
      "enabled": true,
      "terms": [
        {}
      ],
      "require_kyc": false
    }
  ]
}

List locations

GET/locations

Optional filter: datacenter_id.

Query parameters

  • lang string or null
    fa (default) or en for names and descriptions. Accept-Language is honoured too.
  • datacenter_id integer or null
Response fields 8

data[]

  • id integer required
  • datacenter_id integer required
  • name string required
  • country string required
  • country_code string required
  • flag string or null
  • active boolean
  • status string or null

Errors401429

curl "https://api.nexnode.cloud/api/v1/locations" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/locations",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/locations');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": 123,
      "datacenter_id": 1,
      "name": "Nex1-123",
      "country": "Germany",
      "country_code": "DE",
      "flag": "🇩🇪",
      "active": true,
      "status": "online"
    }
  ]
}

One-click apps

GET/catalog/apps

The whole catalogue, or with server_id and template_id only the apps that plan and template can run. Empty when apps are not open to this account.

Query parameters

  • lang string or null
    fa (default) or en for names and descriptions. Accept-Language is honoured too.
  • server_id integer or null
    With template_id: only apps that plan + template can run.
  • template_id integer or null
Response fields 17

data[]

  • id string required
  • name string required
  • category string required
  • description string or null required
  • requires array of strings required
  • conflicts array of strings required
  • ports array of strings required
  • min_memory_mb integer required
  • min_disk_gb integer required
  • os_families array of strings required
  • inputs array of objects required
  • inputs[].key string required
  • inputs[].label string required
  • inputs[].kind string required
  • inputs[].required boolean
  • inputs[].default string or null
  • inputs[].help string or null

Errors401404

curl "https://api.nexnode.cloud/api/v1/catalog/apps" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/catalog/apps",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/catalog/apps');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": "n8n",
      "name": "Nex1-123",
      "category": "automation",
      "description": null,
      "requires": [],
      "conflicts": [],
      "ports": [],
      "min_memory_mb": 1,
      "min_disk_gb": 1,
      "os_families": [],
      "inputs": [
        {
          "key": "DOMAIN",
          "label": "Domain",
          "kind": "text",
          "required": false,
          "default": null,
          "help": null
        }
      ]
    }
  ]
}

Price quote

POST/quote

The exact first charge for a plan, features and template, and whether the wallet (minus reserved pending orders) covers it.

Body

  • server_id integer required
  • term string default hourly
  • template_id integer or null
    Apply the same forced-feature rules as a deploy (a Windows template always bills IPv4).
  • active_features array of strings
Response fields 10

data

  • server_id integer required
  • term string required
  • active_features array of strings required
    Echoed back; forced features may add ids you did not send.
  • cost number required
    First charge: one term plus the creation fee.
  • creation_fee number required
  • recurring number required
    Charged per term after the first.
  • balance number required
  • reserved number required
  • sufficient_balance boolean required
  • difference number required
    How much is missing when sufficient_balance is false.

Errors400401404

curl -X POST "https://api.nexnode.cloud/api/v1/quote" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "server_id": 42,
    "term": "hourly"
  }'
import os

import requests

response = requests.post(
    "https://api.nexnode.cloud/api/v1/quote",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
    json={
        "server_id": 42,
        "term": "hourly",
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/quote');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'server_id' => 42,
        'term' => 'hourly',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "server_id": 42,
    "term": "hourly",
    "active_features": [],
    "cost": 0.0112,
    "creation_fee": 0.0112,
    "recurring": 0.0112,
    "balance": 0.0112,
    "reserved": 0.0112,
    "sufficient_balance": true,
    "difference": 0.0112
  }
}

Instances

Servers you own: order one, read it with its credentials, rename it, run power and rebuild actions, resize it, delete it.

Create instance

POST/instances

Starts a deploy and returns an order id to poll. Send an Idempotency-Key header: a retry with the same key and body returns the original order instead of creating a second server.

Body

  • server_id integer required
    Catalog server id from GET /catalog/servers.
  • template_id integer required
    OS template id for the chosen server. Ignored when snapshot_id is set: the snapshot's OS is used.
  • term string required
    Billing term. Only hourly is currently supported.
  • snapshot_id integer or null
    Build the server from one of your snapshots instead of a template. The snapshot must be available and compatible with the plan (same datacenter, disk at least the snapshot's, same architecture, and the snapshot's location unless the datacenter's snapshot config has cross_location). apps cannot be combined with it.
  • active_features array of strings
    Feature ids to enable (features[].id from GET /catalog/servers). Features whose required_for_os_types includes the template's OS are enabled and billed even if omitted.
  • hostname string or null
    Optional hostname (RFC 1123 labels, max 63 chars). Generated when omitted.
  • apps array of strings
    One-click apps (ids from GET /catalog/apps) to install once the server is up. Dependencies are added automatically.
  • app_inputs object
    Per-app inputs, {app_id: {KEY: value}}. Every input is optional and has a documented default.
Response fields 3

data

  • order_id integer required
    Poll GET /orders/{order_id} until status leaves pending.
  • price number required
    What this order charges when it completes.
  • apps array of strings required
    Apps queued for install, in install order.

Errors400401402403404409422429502

curl -X POST "https://api.nexnode.cloud/api/v1/instances" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "server_id": 42,
    "template_id": 7,
    "term": "hourly",
    "active_features": ["12", "14"],
    "apps": ["docker", "n8n"],
    "app_inputs": {
      "n8n": {
        "DOMAIN": "n8n.example.com"
      }
    }
  }'
import os
import uuid

import requests

response = requests.post(
    "https://api.nexnode.cloud/api/v1/instances",
    headers={
        "X-API-Token": os.environ["NEXNODE_TOKEN"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "server_id": 42,
        "template_id": 7,
        "term": "hourly",
        "active_features": ["12", "14"],
        "apps": ["docker", "n8n"],
        "app_inputs": {
            "n8n": {
                "DOMAIN": "n8n.example.com",
            },
        },
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'server_id' => 42,
        'template_id' => 7,
        'term' => 'hourly',
        'active_features' => ['12', '14'],
        'apps' => ['docker', 'n8n'],
        'app_inputs' => [
            'n8n' => [
                'DOMAIN' => 'n8n.example.com',
            ],
        ],
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response201
{
  "success": true,
  "data": {
    "order_id": 9001,
    "price": 0.0112,
    "apps": []
  }
}

List instances

GET/instances

Active servers by default; only_active=false includes canceled and expired ones. Newest first.

Query parameters

  • limit integer or null
    Page size (1-500). Omit for everything.
  • offset integer default 0
  • only_active boolean default true
    False includes canceled and expired instances.
Response fields 22

data[]

  • id integer required
  • name string required
  • status string or null required
    online / offline / provider-specific; refreshed on GET /instances/{id}.
  • active boolean required
  • hostname string or null required
  • server_product_id integer required
  • ipv4 string or null
  • ipv6 string or null
  • term string or null
  • renewal_due string or null
  • renew boolean
  • locked boolean
  • lock_reason string or null
  • created_at string or null
  • expired_at string or null
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • costs number or null
    Extra recurring costs (USD per term).
  • paid_amount number or null
    Total charged so far (USD).
  • actions array of strings
  • snapshots boolean
    Whether snapshots can be taken of this instance (/instances/{id}/snapshots).

Errors400401429

curl "https://api.nexnode.cloud/api/v1/instances" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/instances",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": 123,
      "name": "Nex1-123",
      "status": "online",
      "active": true,
      "hostname": "Nex1-123",
      "server_product_id": 42,
      "ipv4": "203.0.113.7",
      "ipv6": "2001:db8::7",
      "term": "hourly",
      "renewal_due": "2026-09-16T10:00:00+00:00",
      "renew": true,
      "locked": false,
      "lock_reason": null,
      "created_at": "2026-09-16T10:00:00+00:00",
      "expired_at": "2026-09-16T10:00:00+00:00",
      "datacenter_id": 1,
      "location_id": 3,
      "template_id": 7,
      "costs": 0.0112,
      "paid_amount": 0.0112,
      "actions": ["reboot"],
      "snapshots": false
    }
  ]
}

Get instance

GET/instances/{instance_id}

Full detail including credentials, traffic and queued apps. refresh=true asks the provider for the live status first.

Path parameters

  • instance_id integer required

Query parameters

  • refresh boolean default false
    Ask the provider for the current usage first (slower).
Response fields 57

data

  • id integer required
  • name string required
  • status string or null required
    online / offline / provider-specific; refreshed on GET /instances/{id}.
  • active boolean required
  • hostname string or null required
  • server_product_id integer required
  • ipv4 string or null
  • ipv6 string or null
  • term string or null
  • renewal_due string or null
  • renew boolean
  • locked boolean
  • lock_reason string or null
  • created_at string or null
  • expired_at string or null
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • costs number or null
    Extra recurring costs (USD per term).
  • paid_amount number or null
    Total charged so far (USD).
  • actions array of strings
  • snapshots boolean
    Whether snapshots can be taken of this instance (/instances/{id}/snapshots).
  • server_product object or null
  • location object or null
  • location.id integer required
  • location.datacenter_id integer required
  • location.name string required
  • location.country string required
  • location.country_code string required
  • location.flag string or null
  • location.active boolean
  • location.status string or null
  • datacenter object or null
  • datacenter.id integer required
  • datacenter.name string required
  • datacenter.description string or null
  • datacenter.status string or null
  • datacenter.enabled boolean
  • datacenter.terms array of objects
    Enabled billing terms.
  • datacenter.require_kyc boolean
  • template object or null
  • traffic object or null
  • traffic.enabled boolean required
  • traffic.included integer required
    GB per 30 days; 0 means unlimited.
  • traffic.used integer required
  • traffic.overage integer required
  • traffic.allow_overage boolean required
  • traffic.cycle_start_date string or null required
  • credentials object or null
  • credentials.username string or null required
  • credentials.password string or null required
  • credentials.port integer or null required
    SSH or RDP port.
  • credentials.ipv4 string or null required
  • credentials.ipv6 string or null required
  • credentials.pending boolean required
    True while the provider has not delivered a password or an address yet.
  • apps array of objects
  • ip_change_cost number default 0.0
    USD charged for one change_ip on this instance; 0 where the change is free. Where it is set, the new address is a clean one, there is no wait between changes, and the action must carry accept_cost.

Errors401404429

curl "https://api.nexnode.cloud/api/v1/instances/123" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/instances/123",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "active": true,
    "hostname": "Nex1-123",
    "server_product_id": 42,
    "ipv4": "203.0.113.7",
    "ipv6": "2001:db8::7",
    "term": "hourly",
    "renewal_due": "2026-09-16T10:00:00+00:00",
    "renew": true,
    "locked": false,
    "lock_reason": null,
    "created_at": "2026-09-16T10:00:00+00:00",
    "expired_at": "2026-09-16T10:00:00+00:00",
    "datacenter_id": 1,
    "location_id": 3,
    "template_id": 7,
    "costs": 0.0112,
    "paid_amount": 0.0112,
    "actions": ["reboot"],
    "snapshots": false,
    "server_product": {},
    "location": {
      "id": 3,
      "datacenter_id": 1,
      "name": "Nex1-123",
      "country": "Germany",
      "country_code": "DE",
      "flag": "🇩🇪",
      "active": true,
      "status": "online"
    },
    "datacenter": {
      "id": 1,
      "name": "EU Central",
      "description": "Example DC",
      "status": "available",
      "enabled": true,
      "terms": [
        {}
      ],
      "require_kyc": false
    },
    "template": {},
    "traffic": {
      "enabled": true,
      "included": 2000,
      "used": 10,
      "overage": 0,
      "allow_overage": true,
      "cycle_start_date": "2026-09-16"
    },
    "credentials": {
      "username": "root",
      "password": "hX7kq2Lp9vQe",
      "port": 22,
      "ipv4": "203.0.113.7",
      "ipv6": "2001:db8::7",
      "pending": true
    },
    "apps": [
      {}
    ],
    "ip_change_cost": 0.0
  }
}

Update instance

PATCH/instances/{instance_id}

Rename, set a note, or switch auto-renew. Returns the updated instance.

Path parameters

  • instance_id integer required

Body

  • name string or null
    Display name (max 64 chars).
  • note string or null
    Free-form note (max 512 chars).
  • renew boolean or null
    Auto-renew. False lets the instance expire at renewal_due.
Response fields 57

data

  • id integer required
  • name string required
  • status string or null required
    online / offline / provider-specific; refreshed on GET /instances/{id}.
  • active boolean required
  • hostname string or null required
  • server_product_id integer required
  • ipv4 string or null
  • ipv6 string or null
  • term string or null
  • renewal_due string or null
  • renew boolean
  • locked boolean
  • lock_reason string or null
  • created_at string or null
  • expired_at string or null
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • costs number or null
    Extra recurring costs (USD per term).
  • paid_amount number or null
    Total charged so far (USD).
  • actions array of strings
  • snapshots boolean
    Whether snapshots can be taken of this instance (/instances/{id}/snapshots).
  • server_product object or null
  • location object or null
  • location.id integer required
  • location.datacenter_id integer required
  • location.name string required
  • location.country string required
  • location.country_code string required
  • location.flag string or null
  • location.active boolean
  • location.status string or null
  • datacenter object or null
  • datacenter.id integer required
  • datacenter.name string required
  • datacenter.description string or null
  • datacenter.status string or null
  • datacenter.enabled boolean
  • datacenter.terms array of objects
    Enabled billing terms.
  • datacenter.require_kyc boolean
  • template object or null
  • traffic object or null
  • traffic.enabled boolean required
  • traffic.included integer required
    GB per 30 days; 0 means unlimited.
  • traffic.used integer required
  • traffic.overage integer required
  • traffic.allow_overage boolean required
  • traffic.cycle_start_date string or null required
  • credentials object or null
  • credentials.username string or null required
  • credentials.password string or null required
  • credentials.port integer or null required
    SSH or RDP port.
  • credentials.ipv4 string or null required
  • credentials.ipv6 string or null required
  • credentials.pending boolean required
    True while the provider has not delivered a password or an address yet.
  • apps array of objects
  • ip_change_cost number default 0.0
    USD charged for one change_ip on this instance; 0 where the change is free. Where it is set, the new address is a clean one, there is no wait between changes, and the action must carry accept_cost.

Errors400401404409

curl -X PATCH "https://api.nexnode.cloud/api/v1/instances/123" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "web-01",
    "note": "Customer 4411, production",
    "renew": true
  }'
import os

import requests

response = requests.patch(
    "https://api.nexnode.cloud/api/v1/instances/123",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
    json={
        "name": "web-01",
        "note": "Customer 4411, production",
        "renew": True,
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'name' => 'web-01',
        'note' => 'Customer 4411, production',
        'renew' => true,
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "active": true,
    "hostname": "Nex1-123",
    "server_product_id": 42,
    "ipv4": "203.0.113.7",
    "ipv6": "2001:db8::7",
    "term": "hourly",
    "renewal_due": "2026-09-16T10:00:00+00:00",
    "renew": true,
    "locked": false,
    "lock_reason": null,
    "created_at": "2026-09-16T10:00:00+00:00",
    "expired_at": "2026-09-16T10:00:00+00:00",
    "datacenter_id": 1,
    "location_id": 3,
    "template_id": 7,
    "costs": 0.0112,
    "paid_amount": 0.0112,
    "actions": ["reboot"],
    "snapshots": false,
    "server_product": {},
    "location": {
      "id": 3,
      "datacenter_id": 1,
      "name": "Nex1-123",
      "country": "Germany",
      "country_code": "DE",
      "flag": "🇩🇪",
      "active": true,
      "status": "online"
    },
    "datacenter": {
      "id": 1,
      "name": "EU Central",
      "description": "Example DC",
      "status": "available",
      "enabled": true,
      "terms": [
        {}
      ],
      "require_kyc": false
    },
    "template": {},
    "traffic": {
      "enabled": true,
      "included": 2000,
      "used": 10,
      "overage": 0,
      "allow_overage": true,
      "cycle_start_date": "2026-09-16"
    },
    "credentials": {
      "username": "root",
      "password": "hX7kq2Lp9vQe",
      "port": 22,
      "ipv4": "203.0.113.7",
      "ipv6": "2001:db8::7",
      "pending": true
    },
    "apps": [
      {}
    ],
    "ip_change_cost": 0.0
  }
}

Instance actions

POST/instances/{instance_id}/actions

power_on, power_off, reboot, rebuild (template_id, optional apps), reset_password, change_ip, console. actions on the instance says which ones this plan supports. Where the instance's ip_change_cost is not 0, change_ip gives a clean address, is charged, and needs accept_cost.

Path parameters

  • instance_id integer required

Body

  • action string required
    One of: power_on, power_off, reboot, rebuild, reset_password, change_ip, console, resize, update_metadata.
  • template_id integer or null
    Required for rebuild.
  • server_id integer or null
    Required for resize: the target plan, one of GET /instances/{id}/resize-options.
  • accept_cost number or null
    change_ip on an instance whose ip_change_cost is not 0: the price you agree to, at least ip_change_cost. Without it the call answers 409 cost_unconfirmed and changes nothing.
  • apps array of strings
    rebuild only: apps to install on the new disk.
  • app_inputs object
    rebuild only.
  • name string or null
    update_metadata only (prefer PATCH).
  • note string or null
    update_metadata only (prefer PATCH).
Response fields 11

data

  • action string required
  • success boolean
  • password string or null
    reset_password: the new password.
  • ipv4 string or null
    change_ip: the new address.
  • clean boolean or null
    change_ip where it is paid for: whether the new address came from the clean pool. false means none was ready, the instance got an ordinary one and nothing was charged; the next free one waits out the window.
  • debt number or null
    change_ip: USD booked as debt because the wallet no longer covered the price once the address was changed.
  • console_url string or null
    console: short-lived URL.
  • console_password string or null
  • queued_apps array of strings or null
    rebuild: apps queued for the new disk.
  • charged number or null
    resize: USD charged now for the rest of the current term. change_ip where it is paid for: USD charged for the new address.
  • server_product_id integer or null
    resize: the plan the instance is on now.

Errors400401402404409429502503

curl -X POST "https://api.nexnode.cloud/api/v1/instances/123/actions" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "reboot"
  }'
import os

import requests

response = requests.post(
    "https://api.nexnode.cloud/api/v1/instances/123/actions",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
    json={
        "action": "reboot",
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123/actions');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'action' => 'reboot',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "action": "reboot",
    "success": true,
    "password": "hX7kq2Lp9vQe",
    "ipv4": "203.0.113.7",
    "clean": true,
    "debt": 1.5,
    "console_url": null,
    "console_password": null,
    "queued_apps": [],
    "charged": 0.0112,
    "server_product_id": 42
  }
}

Resize options

GET/instances/{instance_id}/resize-options

The plans this instance can move to (bigger in every dimension, same location), each with what it costs now and per term after. Empty when the plan cannot be resized.

Path parameters

  • instance_id integer required
Response fields 14

data

  • instance_id integer required
  • current_server_product_id integer required
  • term string required
  • options array of objects required
  • options[].id integer required
  • options[].name string required
  • options[].type string required
  • options[].cpu integer required
  • options[].memory number required
  • options[].disk integer required
  • options[].price number or null required
    Plan price on the instance's own billing term.
  • options[].term string required
  • options[].charge_now number required
    USD charged at once: the price difference prorated over what is left of the current term.
  • options[].new_cost number required
    What the instance will cost per term from the next renewal, features included.

Errors401404

curl "https://api.nexnode.cloud/api/v1/instances/123/resize-options" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/instances/123/resize-options",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123/resize-options');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "instance_id": 123,
    "current_server_product_id": 1,
    "term": "hourly",
    "options": [
      {
        "id": 123,
        "name": "Nex1-123",
        "type": "cloud",
        "cpu": 2,
        "memory": 1.5,
        "disk": 40,
        "price": 0.0112,
        "term": "hourly",
        "charge_now": 0.0112,
        "new_cost": 0.0112
      }
    ]
  }
}

Traffic usage

GET/instances/{instance_id}/traffic

Included, used and overage GB for the current cycle. refresh=true asks the provider for the current counter first.

Path parameters

  • instance_id integer required

Query parameters

  • refresh boolean default false
    Ask the provider for the current usage first (slower).
Response fields 6

data

  • enabled boolean required
  • included integer required
    GB per 30 days; 0 means unlimited.
  • used integer required
  • overage integer required
  • allow_overage boolean required
  • cycle_start_date string or null required

Errors401404

curl "https://api.nexnode.cloud/api/v1/instances/123/traffic" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/instances/123/traffic",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123/traffic');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "enabled": true,
    "included": 2000,
    "used": 10,
    "overage": 0,
    "allow_overage": true,
    "cycle_start_date": "2026-09-16"
  }
}

Delete instance

DELETE/instances/{instance_id}

Cancels the instance: billing stops and the provider-side deletion is queued. Returns once the instance is inactive. Idempotent.

Path parameters

  • instance_id integer required
Response fields 3

data

  • id integer required
  • status string required
    The instance is inactive and its deletion is queued at the provider.
  • active boolean

Errors401404429500

curl -X DELETE "https://api.nexnode.cloud/api/v1/instances/123" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.delete(
    "https://api.nexnode.cloud/api/v1/instances/123",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "status": "canceled",
    "active": false
  }
}

Orders

Deploys in flight. An order becomes an instance when the datacenter finishes building it.

List orders

GET/orders

This account's API orders still pending or finished in the last 24 hours, newest first.

Response fields 64

data

  • order_id integer required
  • status string requiredpending, deployed, timed_out
  • success boolean required
    True only when status is deployed.
  • created_at string or null
  • finished_at string or null
  • server object or null
  • server.id integer required
  • server.name string required
  • server.status string or null required
    online / offline / provider-specific; refreshed on GET /instances/{id}.
  • server.active boolean required
  • server.hostname string or null required
  • server.server_product_id integer required
  • server.ipv4 string or null
  • server.ipv6 string or null
  • server.term string or null
  • server.renewal_due string or null
  • server.renew boolean
  • server.locked boolean
  • server.lock_reason string or null
  • server.created_at string or null
  • server.expired_at string or null
  • server.datacenter_id integer or null
  • server.location_id integer or null
  • server.template_id integer or null
  • server.costs number or null
    Extra recurring costs (USD per term).
  • server.paid_amount number or null
    Total charged so far (USD).
  • server.actions array of strings
  • server.snapshots boolean
    Whether snapshots can be taken of this instance (/instances/{id}/snapshots).
  • server.server_product object or null
  • server.location object or null
  • server.location.id integer required
  • server.location.datacenter_id integer required
  • server.location.name string required
  • server.location.country string required
  • server.location.country_code string required
  • server.location.flag string or null
  • server.location.active boolean
  • server.location.status string or null
  • server.datacenter object or null
  • server.datacenter.id integer required
  • server.datacenter.name string required
  • server.datacenter.description string or null
  • server.datacenter.status string or null
  • server.datacenter.enabled boolean
  • server.datacenter.terms array of objects
    Enabled billing terms.
  • server.datacenter.require_kyc boolean
  • server.template object or null
  • server.traffic object or null
  • server.traffic.enabled boolean required
  • server.traffic.included integer required
    GB per 30 days; 0 means unlimited.
  • server.traffic.used integer required
  • server.traffic.overage integer required
  • server.traffic.allow_overage boolean required
  • server.traffic.cycle_start_date string or null required
  • server.credentials object or null
  • server.credentials.username string or null required
  • server.credentials.password string or null required
  • server.credentials.port integer or null required
    SSH or RDP port.
  • server.credentials.ipv4 string or null required
  • server.credentials.ipv6 string or null required
  • server.credentials.pending boolean required
    True while the provider has not delivered a password or an address yet.
  • server.apps array of objects
  • server.ip_change_cost number default 0.0
    USD charged for one change_ip on this instance; 0 where the change is free. Where it is set, the new address is a clean one, there is no wait between changes, and the action must carry accept_cost.
  • reference string or null
    On timed_out: the support reference to quote; the same code the customer sees in Telegram.

Errors401

curl "https://api.nexnode.cloud/api/v1/orders" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/orders",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/orders');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "order_id": 9001,
    "status": "pending",
    "success": true,
    "created_at": "2026-09-16T10:00:00+00:00",
    "finished_at": "2026-09-16T10:00:00+00:00",
    "server": {
      "id": 42,
      "name": "Nex1-123",
      "status": "online",
      "active": true,
      "hostname": "Nex1-123",
      "server_product_id": 42,
      "ipv4": "203.0.113.7",
      "ipv6": "2001:db8::7",
      "term": "hourly",
      "renewal_due": "2026-09-16T10:00:00+00:00",
      "renew": true,
      "locked": false,
      "lock_reason": null,
      "created_at": "2026-09-16T10:00:00+00:00",
      "expired_at": "2026-09-16T10:00:00+00:00",
      "datacenter_id": 1,
      "location_id": 3,
      "template_id": 7,
      "costs": 0.0112,
      "paid_amount": 0.0112,
      "actions": ["reboot"],
      "snapshots": false,
      "server_product": {},
      "location": {
        "id": 3,
        "datacenter_id": 1,
        "name": "Nex1-123",
        "country": "Germany",
        "country_code": "DE",
        "flag": "🇩🇪",
        "active": true,
        "status": "online"
      },
      "datacenter": {
        "id": 1,
        "name": "EU Central",
        "description": "Example DC",
        "status": "available",
        "enabled": true,
        "terms": [
          {}
        ],
        "require_kyc": false
      },
      "template": {},
      "traffic": {
        "enabled": true,
        "included": 2000,
        "used": 10,
        "overage": 0,
        "allow_overage": true,
        "cycle_start_date": "2026-09-16"
      },
      "credentials": {
        "username": "root",
        "password": "hX7kq2Lp9vQe",
        "port": 22,
        "ipv4": "203.0.113.7",
        "ipv6": "2001:db8::7",
        "pending": true
      },
      "apps": [
        {}
      ],
      "ip_change_cost": 0.0
    },
    "reference": null
  }
}

Order status

GET/orders/{order_id}

Poll while status is pending; when deployed, server is the full instance. Terminal orders stay readable for 24 hours, then 404.

Path parameters

  • order_id integer required
Response fields 64

data

  • order_id integer required
  • status string requiredpending, deployed, timed_out
  • success boolean required
    True only when status is deployed.
  • created_at string or null
  • finished_at string or null
  • server object or null
  • server.id integer required
  • server.name string required
  • server.status string or null required
    online / offline / provider-specific; refreshed on GET /instances/{id}.
  • server.active boolean required
  • server.hostname string or null required
  • server.server_product_id integer required
  • server.ipv4 string or null
  • server.ipv6 string or null
  • server.term string or null
  • server.renewal_due string or null
  • server.renew boolean
  • server.locked boolean
  • server.lock_reason string or null
  • server.created_at string or null
  • server.expired_at string or null
  • server.datacenter_id integer or null
  • server.location_id integer or null
  • server.template_id integer or null
  • server.costs number or null
    Extra recurring costs (USD per term).
  • server.paid_amount number or null
    Total charged so far (USD).
  • server.actions array of strings
  • server.snapshots boolean
    Whether snapshots can be taken of this instance (/instances/{id}/snapshots).
  • server.server_product object or null
  • server.location object or null
  • server.location.id integer required
  • server.location.datacenter_id integer required
  • server.location.name string required
  • server.location.country string required
  • server.location.country_code string required
  • server.location.flag string or null
  • server.location.active boolean
  • server.location.status string or null
  • server.datacenter object or null
  • server.datacenter.id integer required
  • server.datacenter.name string required
  • server.datacenter.description string or null
  • server.datacenter.status string or null
  • server.datacenter.enabled boolean
  • server.datacenter.terms array of objects
    Enabled billing terms.
  • server.datacenter.require_kyc boolean
  • server.template object or null
  • server.traffic object or null
  • server.traffic.enabled boolean required
  • server.traffic.included integer required
    GB per 30 days; 0 means unlimited.
  • server.traffic.used integer required
  • server.traffic.overage integer required
  • server.traffic.allow_overage boolean required
  • server.traffic.cycle_start_date string or null required
  • server.credentials object or null
  • server.credentials.username string or null required
  • server.credentials.password string or null required
  • server.credentials.port integer or null required
    SSH or RDP port.
  • server.credentials.ipv4 string or null required
  • server.credentials.ipv6 string or null required
  • server.credentials.pending boolean required
    True while the provider has not delivered a password or an address yet.
  • server.apps array of objects
  • server.ip_change_cost number default 0.0
    USD charged for one change_ip on this instance; 0 where the change is free. Where it is set, the new address is a clean one, there is no wait between changes, and the action must carry accept_cost.
  • reference string or null
    On timed_out: the support reference to quote; the same code the customer sees in Telegram.

Errors401404429

curl "https://api.nexnode.cloud/api/v1/orders/9001" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/orders/9001",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/orders/9001');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "order_id": 9001,
    "status": "pending",
    "success": true,
    "created_at": "2026-09-16T10:00:00+00:00",
    "finished_at": "2026-09-16T10:00:00+00:00",
    "server": {
      "id": 42,
      "name": "Nex1-123",
      "status": "online",
      "active": true,
      "hostname": "Nex1-123",
      "server_product_id": 42,
      "ipv4": "203.0.113.7",
      "ipv6": "2001:db8::7",
      "term": "hourly",
      "renewal_due": "2026-09-16T10:00:00+00:00",
      "renew": true,
      "locked": false,
      "lock_reason": null,
      "created_at": "2026-09-16T10:00:00+00:00",
      "expired_at": "2026-09-16T10:00:00+00:00",
      "datacenter_id": 1,
      "location_id": 3,
      "template_id": 7,
      "costs": 0.0112,
      "paid_amount": 0.0112,
      "actions": ["reboot"],
      "snapshots": false,
      "server_product": {},
      "location": {
        "id": 3,
        "datacenter_id": 1,
        "name": "Nex1-123",
        "country": "Germany",
        "country_code": "DE",
        "flag": "🇩🇪",
        "active": true,
        "status": "online"
      },
      "datacenter": {
        "id": 1,
        "name": "EU Central",
        "description": "Example DC",
        "status": "available",
        "enabled": true,
        "terms": [
          {}
        ],
        "require_kyc": false
      },
      "template": {},
      "traffic": {
        "enabled": true,
        "included": 2000,
        "used": 10,
        "overage": 0,
        "allow_overage": true,
        "cycle_start_date": "2026-09-16"
      },
      "credentials": {
        "username": "root",
        "password": "hX7kq2Lp9vQe",
        "port": 22,
        "ipv4": "203.0.113.7",
        "ipv6": "2001:db8::7",
        "pending": true
      },
      "apps": [
        {}
      ],
      "ip_change_cost": 0.0
    },
    "reference": null
  }
}

Apps

One-click applications installed over SSH after the server is up.

App installs

GET/instances/{instance_id}/apps

Every queued, running, finished or failed one-click install on the instance, newest first, with its stage and log tail.

Path parameters

  • instance_id integer required
Response fields 13

data

  • server_id integer required
  • supported boolean required
  • installs array of objects required
  • installs[].app_id string required
  • installs[].name string required
  • installs[].status string required
    queued / installing / installed / failed
  • installs[].stage string required
    waiting / preparing / running / done / failed / auth_failed
  • installs[].attempts integer required
  • installs[].result object required
    What the install reported (URLs, generated credentials).
  • installs[].error string required
  • installs[].log_tail string required
    Tail of the install log; the only place a failure explains itself.
  • installs[].started_at string or null required
  • installs[].finished_at string or null required

Errors401404

curl "https://api.nexnode.cloud/api/v1/instances/123/apps" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/instances/123/apps",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123/apps');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "server_id": 42,
    "supported": true,
    "installs": [
      {
        "app_id": "n8n",
        "name": "Nex1-123",
        "status": "online",
        "stage": "done",
        "attempts": 1,
        "result": {},
        "error": "The server did not accept SSH",
        "log_tail": "n8n is listening on 5678",
        "started_at": "2026-09-16T10:00:00+00:00",
        "finished_at": "2026-09-16T10:00:00+00:00"
      }
    ]
  }
}

Install apps

POST/instances/{instance_id}/apps

Queue one-click apps on a running instance. The stored root password must still be valid; a changed one fails the install with auth_failed (see GET /instances/{id}/apps).

Path parameters

  • instance_id integer required

Body

  • apps array of strings required
    App ids to install; dependencies are added automatically.
  • app_inputs object
    Per-app inputs, {app_id: {KEY: value}}. Every input is optional.
Response fields 2

data

  • server_id integer required
  • queued array of strings required

Errors400401403404409503

curl -X POST "https://api.nexnode.cloud/api/v1/instances/123/apps" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "apps": ["n8n"],
    "app_inputs": {
      "n8n": {
        "DOMAIN": "n8n.example.com"
      }
    }
  }'
import os

import requests

response = requests.post(
    "https://api.nexnode.cloud/api/v1/instances/123/apps",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
    json={
        "apps": ["n8n"],
        "app_inputs": {
            "n8n": {
                "DOMAIN": "n8n.example.com",
            },
        },
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123/apps');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'apps' => ['n8n'],
        'app_inputs' => [
            'n8n' => [
                'DOMAIN' => 'n8n.example.com',
            ],
        ],
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response202
{
  "success": true,
  "data": {
    "server_id": 42,
    "queued": []
  }
}

Snapshots

Point-in-time images of an instance, billed hourly by size: restore in place, delete, or order new instances from one (POST /instances with snapshot_id).

Create snapshot

POST/instances/{instance_id}/snapshots

Starts a snapshot of the instance; the server stays online. Returns the snapshot in creating; poll GET /snapshots/{id} until it is available. The first term is charged then, from the real size.

Path parameters

  • instance_id integer required

Body

  • name string or null
    Display name (max 64 chars). Defaults to the instance name and the time.
Response fields 26

data

  • id integer required
  • name string required
  • status string required
    creating, available, restoring, failed, expired or deleted.
  • note string or null
  • locked boolean
  • lock_reason string or null
    unpaid when the balance was short at renewal; the snapshot cannot be used until it is paid.
  • size_gb number or null
  • price number or null
    USD per hour, fixed from the real size when the snapshot became available. Accrued every hour and charged to the wallet once the accrued amount reaches a tenth of a cent.
  • price_monthly number or null
    The hourly rate over a month, for display.
  • term string default hourly
  • accrued number or null
    USD accrued on the snapshot and not yet charged.
  • renewal_due string or null
    Start of the next hour to be accounted.
  • created_at string or null
  • available_at string or null
  • expired_at string or null
  • instance_id integer or null
    The instance it was taken from; null once that instance is gone.
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • server_product_id integer or null
  • os_type string or null
  • source_name string or null
  • features array of strings
    Names of the features the instance had when the snapshot was taken (its IPv4 add-on, a licence, an extra disk). A clone carries them where its plan offers them, unless the request names its own active_features.
  • local boolean
    True when the snapshot lives on the instance's own disk (a restore point that is deleted with the instance).
  • restore boolean
    Whether POST /snapshots/{id}/restore is available on this datacenter. False where only cloning is possible.
  • paid_amount number or null

Errors400401402403404409502

curl -X POST "https://api.nexnode.cloud/api/v1/instances/123/snapshots" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "before-upgrade"
  }'
import os

import requests

response = requests.post(
    "https://api.nexnode.cloud/api/v1/instances/123/snapshots",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
    json={
        "name": "before-upgrade",
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123/snapshots');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'name' => 'before-upgrade',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response202
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "note": null,
    "locked": false,
    "lock_reason": null,
    "size_gb": 12.5,
    "price": 0.0112,
    "price_monthly": 0.0112,
    "term": "hourly",
    "accrued": 0.0112,
    "renewal_due": "2026-09-16T10:00:00+00:00",
    "created_at": "2026-09-16T10:00:00+00:00",
    "available_at": "2026-09-16T10:00:00+00:00",
    "expired_at": "2026-09-16T10:00:00+00:00",
    "instance_id": 123,
    "datacenter_id": 1,
    "location_id": 3,
    "template_id": 7,
    "server_product_id": 42,
    "os_type": "linux",
    "source_name": null,
    "features": [],
    "local": false,
    "restore": true,
    "paid_amount": 0.0112
  }
}

Instance snapshots

GET/instances/{instance_id}/snapshots

The snapshots taken from this instance. meta.settings carries the datacenter's price per GB, term length and per-instance cap.

Path parameters

  • instance_id integer required
Response fields 26

data[]

  • id integer required
  • name string required
  • status string required
    creating, available, restoring, failed, expired or deleted.
  • note string or null
  • locked boolean
  • lock_reason string or null
    unpaid when the balance was short at renewal; the snapshot cannot be used until it is paid.
  • size_gb number or null
  • price number or null
    USD per hour, fixed from the real size when the snapshot became available. Accrued every hour and charged to the wallet once the accrued amount reaches a tenth of a cent.
  • price_monthly number or null
    The hourly rate over a month, for display.
  • term string default hourly
  • accrued number or null
    USD accrued on the snapshot and not yet charged.
  • renewal_due string or null
    Start of the next hour to be accounted.
  • created_at string or null
  • available_at string or null
  • expired_at string or null
  • instance_id integer or null
    The instance it was taken from; null once that instance is gone.
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • server_product_id integer or null
  • os_type string or null
  • source_name string or null
  • features array of strings
    Names of the features the instance had when the snapshot was taken (its IPv4 add-on, a licence, an extra disk). A clone carries them where its plan offers them, unless the request names its own active_features.
  • local boolean
    True when the snapshot lives on the instance's own disk (a restore point that is deleted with the instance).
  • restore boolean
    Whether POST /snapshots/{id}/restore is available on this datacenter. False where only cloning is possible.
  • paid_amount number or null

Errors401403404

curl "https://api.nexnode.cloud/api/v1/instances/123/snapshots" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/instances/123/snapshots",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/instances/123/snapshots');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": 123,
      "name": "Nex1-123",
      "status": "online",
      "note": null,
      "locked": false,
      "lock_reason": null,
      "size_gb": 12.5,
      "price": 0.0112,
      "price_monthly": 0.0112,
      "term": "hourly",
      "accrued": 0.0112,
      "renewal_due": "2026-09-16T10:00:00+00:00",
      "created_at": "2026-09-16T10:00:00+00:00",
      "available_at": "2026-09-16T10:00:00+00:00",
      "expired_at": "2026-09-16T10:00:00+00:00",
      "instance_id": 123,
      "datacenter_id": 1,
      "location_id": 3,
      "template_id": 7,
      "server_product_id": 42,
      "os_type": "linux",
      "source_name": null,
      "features": [],
      "local": false,
      "restore": true,
      "paid_amount": 0.0112
    }
  ]
}

List snapshots

GET/snapshots

Every snapshot you own, newest first, including those whose instance is already gone (they can still be cloned).

Query parameters

  • include_inactive boolean default false
    Also list deleted, expired and failed snapshots.
Response fields 26

data[]

  • id integer required
  • name string required
  • status string required
    creating, available, restoring, failed, expired or deleted.
  • note string or null
  • locked boolean
  • lock_reason string or null
    unpaid when the balance was short at renewal; the snapshot cannot be used until it is paid.
  • size_gb number or null
  • price number or null
    USD per hour, fixed from the real size when the snapshot became available. Accrued every hour and charged to the wallet once the accrued amount reaches a tenth of a cent.
  • price_monthly number or null
    The hourly rate over a month, for display.
  • term string default hourly
  • accrued number or null
    USD accrued on the snapshot and not yet charged.
  • renewal_due string or null
    Start of the next hour to be accounted.
  • created_at string or null
  • available_at string or null
  • expired_at string or null
  • instance_id integer or null
    The instance it was taken from; null once that instance is gone.
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • server_product_id integer or null
  • os_type string or null
  • source_name string or null
  • features array of strings
    Names of the features the instance had when the snapshot was taken (its IPv4 add-on, a licence, an extra disk). A clone carries them where its plan offers them, unless the request names its own active_features.
  • local boolean
    True when the snapshot lives on the instance's own disk (a restore point that is deleted with the instance).
  • restore boolean
    Whether POST /snapshots/{id}/restore is available on this datacenter. False where only cloning is possible.
  • paid_amount number or null

Errors401403

curl "https://api.nexnode.cloud/api/v1/snapshots" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/snapshots",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/snapshots');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": 123,
      "name": "Nex1-123",
      "status": "online",
      "note": null,
      "locked": false,
      "lock_reason": null,
      "size_gb": 12.5,
      "price": 0.0112,
      "price_monthly": 0.0112,
      "term": "hourly",
      "accrued": 0.0112,
      "renewal_due": "2026-09-16T10:00:00+00:00",
      "created_at": "2026-09-16T10:00:00+00:00",
      "available_at": "2026-09-16T10:00:00+00:00",
      "expired_at": "2026-09-16T10:00:00+00:00",
      "instance_id": 123,
      "datacenter_id": 1,
      "location_id": 3,
      "template_id": 7,
      "server_product_id": 42,
      "os_type": "linux",
      "source_name": null,
      "features": [],
      "local": false,
      "restore": true,
      "paid_amount": 0.0112
    }
  ]
}

Snapshot detail

GET/snapshots/{snapshot_id}

Path parameters

  • snapshot_id integer required
Response fields 26

data

  • id integer required
  • name string required
  • status string required
    creating, available, restoring, failed, expired or deleted.
  • note string or null
  • locked boolean
  • lock_reason string or null
    unpaid when the balance was short at renewal; the snapshot cannot be used until it is paid.
  • size_gb number or null
  • price number or null
    USD per hour, fixed from the real size when the snapshot became available. Accrued every hour and charged to the wallet once the accrued amount reaches a tenth of a cent.
  • price_monthly number or null
    The hourly rate over a month, for display.
  • term string default hourly
  • accrued number or null
    USD accrued on the snapshot and not yet charged.
  • renewal_due string or null
    Start of the next hour to be accounted.
  • created_at string or null
  • available_at string or null
  • expired_at string or null
  • instance_id integer or null
    The instance it was taken from; null once that instance is gone.
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • server_product_id integer or null
  • os_type string or null
  • source_name string or null
  • features array of strings
    Names of the features the instance had when the snapshot was taken (its IPv4 add-on, a licence, an extra disk). A clone carries them where its plan offers them, unless the request names its own active_features.
  • local boolean
    True when the snapshot lives on the instance's own disk (a restore point that is deleted with the instance).
  • restore boolean
    Whether POST /snapshots/{id}/restore is available on this datacenter. False where only cloning is possible.
  • paid_amount number or null

Errors401403404

curl "https://api.nexnode.cloud/api/v1/snapshots/15" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/snapshots/15",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/snapshots/15');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "note": null,
    "locked": false,
    "lock_reason": null,
    "size_gb": 12.5,
    "price": 0.0112,
    "price_monthly": 0.0112,
    "term": "hourly",
    "accrued": 0.0112,
    "renewal_due": "2026-09-16T10:00:00+00:00",
    "created_at": "2026-09-16T10:00:00+00:00",
    "available_at": "2026-09-16T10:00:00+00:00",
    "expired_at": "2026-09-16T10:00:00+00:00",
    "instance_id": 123,
    "datacenter_id": 1,
    "location_id": 3,
    "template_id": 7,
    "server_product_id": 42,
    "os_type": "linux",
    "source_name": null,
    "features": [],
    "local": false,
    "restore": true,
    "paid_amount": 0.0112
  }
}

Update snapshot

PATCH/snapshots/{snapshot_id}

Rename or set a note.

Path parameters

  • snapshot_id integer required

Body

  • name string or null
    Display name (max 64 chars).
  • note string or null
    Free-form note (max 512 chars). Empty string clears it.
Response fields 26

data

  • id integer required
  • name string required
  • status string required
    creating, available, restoring, failed, expired or deleted.
  • note string or null
  • locked boolean
  • lock_reason string or null
    unpaid when the balance was short at renewal; the snapshot cannot be used until it is paid.
  • size_gb number or null
  • price number or null
    USD per hour, fixed from the real size when the snapshot became available. Accrued every hour and charged to the wallet once the accrued amount reaches a tenth of a cent.
  • price_monthly number or null
    The hourly rate over a month, for display.
  • term string default hourly
  • accrued number or null
    USD accrued on the snapshot and not yet charged.
  • renewal_due string or null
    Start of the next hour to be accounted.
  • created_at string or null
  • available_at string or null
  • expired_at string or null
  • instance_id integer or null
    The instance it was taken from; null once that instance is gone.
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • server_product_id integer or null
  • os_type string or null
  • source_name string or null
  • features array of strings
    Names of the features the instance had when the snapshot was taken (its IPv4 add-on, a licence, an extra disk). A clone carries them where its plan offers them, unless the request names its own active_features.
  • local boolean
    True when the snapshot lives on the instance's own disk (a restore point that is deleted with the instance).
  • restore boolean
    Whether POST /snapshots/{id}/restore is available on this datacenter. False where only cloning is possible.
  • paid_amount number or null

Errors400401403404

curl -X PATCH "https://api.nexnode.cloud/api/v1/snapshots/15" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "before-upgrade",
    "note": "Taken before the 2.0 release"
  }'
import os

import requests

response = requests.patch(
    "https://api.nexnode.cloud/api/v1/snapshots/15",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
    json={
        "name": "before-upgrade",
        "note": "Taken before the 2.0 release",
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/snapshots/15');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'name' => 'before-upgrade',
        'note' => 'Taken before the 2.0 release',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "note": null,
    "locked": false,
    "lock_reason": null,
    "size_gb": 12.5,
    "price": 0.0112,
    "price_monthly": 0.0112,
    "term": "hourly",
    "accrued": 0.0112,
    "renewal_due": "2026-09-16T10:00:00+00:00",
    "created_at": "2026-09-16T10:00:00+00:00",
    "available_at": "2026-09-16T10:00:00+00:00",
    "expired_at": "2026-09-16T10:00:00+00:00",
    "instance_id": 123,
    "datacenter_id": 1,
    "location_id": 3,
    "template_id": 7,
    "server_product_id": 42,
    "os_type": "linux",
    "source_name": null,
    "features": [],
    "local": false,
    "restore": true,
    "paid_amount": 0.0112
  }
}

Restore snapshot

POST/snapshots/{snapshot_id}/restore

Puts the snapshot back onto the instance it came from, in place. The instance is powered off during the restore and keeps its addresses; its disk and credentials become what the snapshot holds. Anything changed since the snapshot is lost.

Path parameters

  • snapshot_id integer required
Response fields 26

data

  • id integer required
  • name string required
  • status string required
    creating, available, restoring, failed, expired or deleted.
  • note string or null
  • locked boolean
  • lock_reason string or null
    unpaid when the balance was short at renewal; the snapshot cannot be used until it is paid.
  • size_gb number or null
  • price number or null
    USD per hour, fixed from the real size when the snapshot became available. Accrued every hour and charged to the wallet once the accrued amount reaches a tenth of a cent.
  • price_monthly number or null
    The hourly rate over a month, for display.
  • term string default hourly
  • accrued number or null
    USD accrued on the snapshot and not yet charged.
  • renewal_due string or null
    Start of the next hour to be accounted.
  • created_at string or null
  • available_at string or null
  • expired_at string or null
  • instance_id integer or null
    The instance it was taken from; null once that instance is gone.
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • server_product_id integer or null
  • os_type string or null
  • source_name string or null
  • features array of strings
    Names of the features the instance had when the snapshot was taken (its IPv4 add-on, a licence, an extra disk). A clone carries them where its plan offers them, unless the request names its own active_features.
  • local boolean
    True when the snapshot lives on the instance's own disk (a restore point that is deleted with the instance).
  • restore boolean
    Whether POST /snapshots/{id}/restore is available on this datacenter. False where only cloning is possible.
  • paid_amount number or null

Errors401403404409502

curl -X POST "https://api.nexnode.cloud/api/v1/snapshots/15/restore" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.post(
    "https://api.nexnode.cloud/api/v1/snapshots/15/restore",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/snapshots/15/restore');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "note": null,
    "locked": false,
    "lock_reason": null,
    "size_gb": 12.5,
    "price": 0.0112,
    "price_monthly": 0.0112,
    "term": "hourly",
    "accrued": 0.0112,
    "renewal_due": "2026-09-16T10:00:00+00:00",
    "created_at": "2026-09-16T10:00:00+00:00",
    "available_at": "2026-09-16T10:00:00+00:00",
    "expired_at": "2026-09-16T10:00:00+00:00",
    "instance_id": 123,
    "datacenter_id": 1,
    "location_id": 3,
    "template_id": 7,
    "server_product_id": 42,
    "os_type": "linux",
    "source_name": null,
    "features": [],
    "local": false,
    "restore": true,
    "paid_amount": 0.0112
  }
}

Delete snapshot

DELETE/snapshots/{snapshot_id}

Deletes it at the provider and stops its billing. Not refunded.

Path parameters

  • snapshot_id integer required
Response fields 26

data

  • id integer required
  • name string required
  • status string required
    creating, available, restoring, failed, expired or deleted.
  • note string or null
  • locked boolean
  • lock_reason string or null
    unpaid when the balance was short at renewal; the snapshot cannot be used until it is paid.
  • size_gb number or null
  • price number or null
    USD per hour, fixed from the real size when the snapshot became available. Accrued every hour and charged to the wallet once the accrued amount reaches a tenth of a cent.
  • price_monthly number or null
    The hourly rate over a month, for display.
  • term string default hourly
  • accrued number or null
    USD accrued on the snapshot and not yet charged.
  • renewal_due string or null
    Start of the next hour to be accounted.
  • created_at string or null
  • available_at string or null
  • expired_at string or null
  • instance_id integer or null
    The instance it was taken from; null once that instance is gone.
  • datacenter_id integer or null
  • location_id integer or null
  • template_id integer or null
  • server_product_id integer or null
  • os_type string or null
  • source_name string or null
  • features array of strings
    Names of the features the instance had when the snapshot was taken (its IPv4 add-on, a licence, an extra disk). A clone carries them where its plan offers them, unless the request names its own active_features.
  • local boolean
    True when the snapshot lives on the instance's own disk (a restore point that is deleted with the instance).
  • restore boolean
    Whether POST /snapshots/{id}/restore is available on this datacenter. False where only cloning is possible.
  • paid_amount number or null

Errors401403404409502

curl -X DELETE "https://api.nexnode.cloud/api/v1/snapshots/15" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.delete(
    "https://api.nexnode.cloud/api/v1/snapshots/15",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/snapshots/15');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "name": "Nex1-123",
    "status": "online",
    "note": null,
    "locked": false,
    "lock_reason": null,
    "size_gb": 12.5,
    "price": 0.0112,
    "price_monthly": 0.0112,
    "term": "hourly",
    "accrued": 0.0112,
    "renewal_due": "2026-09-16T10:00:00+00:00",
    "created_at": "2026-09-16T10:00:00+00:00",
    "available_at": "2026-09-16T10:00:00+00:00",
    "expired_at": "2026-09-16T10:00:00+00:00",
    "instance_id": 123,
    "datacenter_id": 1,
    "location_id": 3,
    "template_id": 7,
    "server_product_id": 42,
    "os_type": "linux",
    "source_name": null,
    "features": [],
    "local": false,
    "restore": true,
    "paid_amount": 0.0112
  }
}

Webhooks

One signed HTTPS endpoint per account, and the events it receives. How to check the signature is under Webhooks in the guide.

Register a webhook

PUT/account/webhook

One HTTPS URL per account. Deliveries are signed with secret; see the docs for the signature scheme. Replaces any previous registration.

Body

  • url string required
    HTTPS endpoint that receives every event for this account.
  • secret string required
    16 to 256 characters; used to sign deliveries (HMAC-SHA256). Never returned.
Response fields 3

data

  • url string or null required
  • configured boolean required
  • events array of strings required
    Event names this API can send.

Errors400401

curl -X PUT "https://api.nexnode.cloud/api/v1/account/webhook" \
  -H "X-API-Token: $NEXNODE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/nexnode/webhook",
    "secret": "a-long-random-string-you-generate"
  }'
import os

import requests

response = requests.put(
    "https://api.nexnode.cloud/api/v1/account/webhook",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
    json={
        "url": "https://example.com/nexnode/webhook",
        "secret": "a-long-random-string-you-generate",
    },
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/account/webhook');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'url' => 'https://example.com/nexnode/webhook',
        'secret' => 'a-long-random-string-you-generate',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "url": "https://hooks.example.com/nexnode",
    "configured": true,
    "events": ["order.deployed"]
  }
}

Webhook settings

GET/account/webhook

The registered URL (the secret is never returned) and the event names.

Response fields 3

data

  • url string or null required
  • configured boolean required
  • events array of strings required
    Event names this API can send.

Errors401

curl "https://api.nexnode.cloud/api/v1/account/webhook" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/account/webhook",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/account/webhook');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "url": "https://hooks.example.com/nexnode",
    "configured": true,
    "events": ["order.deployed"]
  }
}

Send a test event

POST/account/webhook/test

Delivered once, without retries, and the endpoint's HTTP status is reported back.

Response fields 2

data

  • delivered boolean required
  • status integer or null required
    HTTP status the endpoint answered with, if it answered.

Errors400401503

curl -X POST "https://api.nexnode.cloud/api/v1/account/webhook/test" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.post(
    "https://api.nexnode.cloud/api/v1/account/webhook/test",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/account/webhook/test');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "delivered": true,
    "status": 1
  }
}

Remove the webhook

DELETE/account/webhook

Response fields 3

data

  • url string or null required
  • configured boolean required
  • events array of strings required
    Event names this API can send.

Errors401

curl -X DELETE "https://api.nexnode.cloud/api/v1/account/webhook" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.delete(
    "https://api.nexnode.cloud/api/v1/account/webhook",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/account/webhook');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "url": "https://hooks.example.com/nexnode",
    "configured": true,
    "events": ["order.deployed"]
  }
}

Events

Every delivery is a POST of {"id", "event", "created_at", "data"}, signed as described under Webhooks. The fields below are the ones inside data.

ping

Sent by POST /account/webhook/test.

data

  • account_id integer required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "ping",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "account_id": 123456
  }
}
order.deployed

A POST /instances order finished and the instance exists. instance_id is the id for every /instances call.

data

  • order_id integer required
  • status string required
  • instance_id integer required
  • server_id integer required
    Catalogue plan id.
  • price number required
    What the order charged (USD).
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "order.deployed",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "order_id": 9001,
    "status": "deployed",
    "instance_id": 123,
    "server_id": 42,
    "price": 0.0097
  }
}
order.timed_out

The provider did not finish within the order window; nothing was created or charged.

data

  • order_id integer required
  • status string required
  • instance_id null required
  • server_id integer required
  • price number required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "order.timed_out",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "order_id": 9002,
    "status": "timed_out",
    "instance_id": null,
    "server_id": 42,
    "price": 0.0097
  }
}
instance.canceled

The instance was canceled. reason is api for your own DELETE, system for expiry, unpaid debt, abuse or an admin.

data

  • instance_id integer required
  • status string required
    Why, as stored on the instance.
  • reason string requiredapi, system
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "instance.canceled",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "instance_id": 123,
    "status": "Expired",
    "reason": "system"
  }
}
instance.password_reset

The root password was reset through the API. Read it from GET /instances/{id}; it is not in the webhook.

data

  • instance_id integer required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "instance.password_reset",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "instance_id": 123
  }
}
instance.ip_changed

The IPv4 address was changed through the API.

data

  • instance_id integer required
  • ipv4 string required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "instance.ip_changed",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "instance_id": 123,
    "ipv4": "203.0.113.7"
  }
}
instance.resized

The instance was moved to another plan through the API. charged is what was taken now for the rest of the current term.

data

  • instance_id integer required
  • server_id integer required
    The new catalog server id.
  • charged number required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "instance.resized",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "instance_id": 123,
    "server_id": 43,
    "charged": 0.005
  }
}
snapshot.created

A snapshot was requested through the API. It starts in creating; poll GET /snapshots/{id} until it is available.

data

  • snapshot_id integer required
  • instance_id integer required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "snapshot.created",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "snapshot_id": 15,
    "instance_id": 123
  }
}
snapshot.restored

A snapshot was restored onto its instance through the API.

data

  • snapshot_id integer required
  • instance_id integer required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "snapshot.restored",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "snapshot_id": 15,
    "instance_id": 123
  }
}
snapshot.deleted

A snapshot was deleted through the API.

data

  • snapshot_id integer required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "snapshot.deleted",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "snapshot_id": 15
  }
}
balance.low

Sent at 24, 12, 6, 2 and 1 hours before renewals exhaust the wallet.

data

  • balance number required
  • hours_until_balance_zero number required
Payload
{
  "id": "6f1c2a1e-4b7d-4c2e-9f3a-2d1b3c4d5e6f",
  "event": "balance.low",
  "created_at": "2026-09-10T10:00:00+00:00",
  "data": {
    "balance": 0.31,
    "hours_until_balance_zero": 11.5
  }
}

Account

Who the key belongs to, wallet balance, reserved funds and payments.

Account

GET/account

The account behind the key, the key's hint and issue date, and the limits that apply. The key itself is never returned.

Response fields 7

data

  • id integer required
    Account id.
  • api_key_hint string or null required
    First characters of the key in use; the key itself is never returned.
  • api_key_created_at string or null required
  • webhook_configured boolean required
  • server_limit integer required
    Maximum active instances.
  • api_order_limit integer required
    Maximum orders provisioning at once.
  • language string required

Errors401

curl "https://api.nexnode.cloud/api/v1/account" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/account",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/account');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "id": 123,
    "api_key_hint": "sk_Ab12Cd34",
    "api_key_created_at": "2026-09-16T10:00:00+00:00",
    "webhook_configured": true,
    "server_limit": 1,
    "api_order_limit": 1,
    "language": "fa"
  }
}

Account balance

GET/account/balance

Wallet balance, debt, money reserved by pending orders, and the estimated hours until renewals exhaust the balance.

Response fields 7

data

  • balance number required
    Current wallet balance (USD).
  • debt number required
    Outstanding debt (USD).
  • reserved number required
    Sum of prices of this account's orders still provisioning; counted against the balance for new orders.
  • available number required
    balance - reserved: what a new order can draw on.
  • hours_until_balance_zero number or null
    Estimated hours until renewal charges exhaust the balance (same simulation as the bot); null if there are no renewable servers or the time cannot be estimated.
  • active_instances integer default 0
  • pending_orders integer default 0

Errors401429

curl "https://api.nexnode.cloud/api/v1/account/balance" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/account/balance",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/account/balance');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "balance": 100.5,
    "debt": 0.0,
    "reserved": 4.5,
    "available": 96.0,
    "hours_until_balance_zero": 48.25,
    "active_instances": 3,
    "pending_orders": 1
  }
}

Payments

GET/account/payments

Top-ups credited to the wallet, newest first.

Query parameters

  • limit integer or null
    Page size (1-500). Omit for everything.
  • offset integer default 0
Response fields 4

data[]

  • id integer required
  • amount number required
    Credited amount (USD).
  • payment_type string or null required
  • paid_at string or null required
    ISO 8601 timestamp.

Errors401429

curl "https://api.nexnode.cloud/api/v1/account/payments" \
  -H "X-API-Token: $NEXNODE_TOKEN"
import os

import requests

response = requests.get(
    "https://api.nexnode.cloud/api/v1/account/payments",
    headers={"X-API-Token": os.environ["NEXNODE_TOKEN"]},
)
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/account/payments');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'X-API-Token: ' . getenv('NEXNODE_TOKEN'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": [
    {
      "id": 123,
      "amount": 0.0112,
      "payment_type": "crypto",
      "paid_at": "2026-09-16T10:00:00+00:00"
    }
  ]
}

System

Health check. No authentication.

Health check

GET/health

No authentication. Same JSON envelope as other routes.

Response fields 2

data

  • status string required
  • api string required

Errors429

curl "https://api.nexnode.cloud/api/v1/health"
import requests

response = requests.get("https://api.nexnode.cloud/api/v1/health")
data = response.json()["data"]
<?php

$ch = curl_init('https://api.nexnode.cloud/api/v1/health');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];
Response200
{
  "success": true,
  "data": {
    "status": "ok",
    "api": "reseller_v1"
  }
}