Pendahuluan
Dokumentasi ini untuk developer mitra NBT Host: agensi dan perusahaan yang meng-hosting pelanggannya di tempat kami dengan merek mereka sendiri. Dengan API ini Anda menghubungkan aplikasi Anda sendiri (penagihan, CRM, formulir pesanan) ke panel: pelanggan yang membayar Anda otomatis mendapatkan akun, situs, dan email, tanpa ada yang perlu masuk ke panel.
Tidak ada API “NBT” terpisah: Anda bekerja langsung dengan API Enhance, di dalam organisasi mitra Anda. Setiap path di halaman ini adalah path API yang sebenarnya. Contoh baca (GET) dijalankan di server kami pada 21 Oktober 2026, dengan Enhance 12.25.13, dan responsnya menunjukkan bentuk yang kami terima (nilainya hanya contoh). Contoh tulis diverifikasi pada organisasi uji sebelum program diluncurkan.
- URL dasar:
https://server.nbt-host.com/api. - Buat token di panel: Pengaturan → Token akses → Membuat token. Header:
Authorization: Bearer <tokenId>_<kunci>. - Hampir semua path diawali
/orgs/{org_id}: organisasi Anda ($NBT_ORG) untuk pelanggan dan paket, organisasi pelanggan ($CLIENT) untuk situs-situsnya. - Alur lengkap pertama: pelanggan baru dengan situs dan email dalam 5 panggilan.
Konsep
Lisensi Enhance sudah termasuk
Lisensi Enhance sudah termasuk dalam harga paket mitra dan disediakan oleh NBT Host. Anda tidak memiliki kontrak langsung dengan Enhance dan tidak membeli lisensi: Anda bekerja di panel Enhance milik NBT Host (klaster kami), dengan merek dan domain Anda sendiri. Server, pembaruan panel, keamanan, dan backup server tetap menjadi tanggung jawab kami.
Pada Mitra 50 dan Mitra 100, VPS yang termasuk dalam paket bergabung ke klaster NBT Host: situs pelanggan Anda berjalan di sana, tetapi Anda tidak mendapatkan akses root, dan server dari penyedia lain tidak dapat ditambahkan.
Paket mitra
Setiap paket memberi Anda organisasi reseller (mitra) dengan batas di bawah ini. Batas tersebut adalah total untuk semua pelanggan Anda sekaligus; nilai pastinya, beserta yang sudah terpakai, bisa dibaca kapan saja dengan GET /orgs/{ORG}/subscriptions (Batas). Nama paket di API tetap seperti di bawah (nbthost_partener_*).
Mitra 30
- Hingga 50 situs
- Hosting web bersama
- 8 GB RAM
- Panel dengan merek dan domain Anda
- Paket di Enhance:
nbthost_partener_30
Mitra 50
- Hingga 100 situs
- VPS termasuk, di klaster NBT Host
- 12 GB RAM · 6 vCPU
- 200 GB SSD atau 100 GB NVMe
- Panel dengan merek dan domain Anda
- Paket di Enhance:
nbthost_partener_50
Mitra 100
- Hingga 250 situs
- VPS termasuk, di klaster NBT Host
- 24 GB RAM · 8 vCPU
- 300 GB SSD atau 150 GB NVMe
- Panel dengan merek dan domain Anda
- Paket di Enhance:
nbthost_partener_100
Objek yang Anda kelola
- Organisasi mitra Anda org · uuid · $NBT_ORG
- Langganan Anda ke paket Mitra subscription · int — sumber daya yang Anda bagikan ke pelanggan
- Paket Anda untuk pelanggan plan · int — Anda buat sendiri dari batas Anda, dengan harga Anda
- Token API Anda access token
- Seorang pelanggan org · uuid · $CLIENT
- Langganan pelanggan ke salah satu paket Anda subscription · int
- Situs-situsnya website · uuid
- Domain: utama, alias, subdomain domain · uuid → zona DNS, sertifikat SSL, kotak surat
- Database MySQL, backup, aplikasi (WordPress)
- Anggota (login dengan peran) — siapa yang masuk ke panel sebagai pelanggan ini
| Istilah | Di API | Artinya |
|---|---|---|
| Organisasi | org (uuid) | Wadah untuk semuanya: organisasi Anda adalah “reseller”, setiap pelanggan adalah organisasi “customer” di bawahnya. |
| Pelanggan | customer | Organisasi yang Anda buat dengan POST /orgs/{ORG}/customers. parentId-nya adalah organisasi Anda. |
| Paket | plan (int) | Sumber daya (situs, penyimpanan, kotak surat, database), fitur (allowances), dan versi PHP. Paket Anda milik organisasi Anda. |
| Langganan | subscription (int) | Hubungan antara organisasi dan paket. Situs dibuat pada sebuah langganan dan memakai kuotanya. Penangguhan dilakukan pada langganan. |
| Situs | website (uuid) | Situs yang di-hosting, dengan pengguna Unix, PHP, file, database, dan email sendiri. Memiliki domain utama. |
| Domain | domain (uuid) | Nama yang terhubung ke situs: primary, alias, atau subdomain. Zona DNS, SSL, dan email diakses lewat domain.id. |
| Login, anggota | login, member | Login adalah orangnya (email + kata sandi) di “realm” Anda; anggota adalah login itu di dalam sebuah organisasi, dengan peran (Owner, SuperAdmin …). |
| Realm | — | Ruang login panel Anda. Pelanggan Anda masuk di domain panel Anda, bukan di server.nbt-host.com. |
Autentikasi
Token, langkah demi langkah di panel
- Masuk ke panel dengan akun mitra Anda (
https://server.nbt-host.comatau domain panel Anda). - Pengaturan → Token akses → Membuat token (dalam bahasa Inggris: Settings → Access tokens → Create token).
- Beri nama sesuai aplikasinya (misalnya “penagihan”) dan pilih peran:
SuperAdminuntuk otomatisasi penuh;Sysadmin,Support, atauBusinessuntuk akses yang lebih terbatas. TokenOwnertidak dapat dibuat. - Tetapkan tanggal kedaluwarsa dan alamat IP server yang memanggil API.
- Panel menampilkan token hanya sekali, dalam bentuk
<tokenId>_<kunci>, beserta id organisasi Anda. Salin keduanya ke pengelola kata sandi atau ke variabel lingkungan aplikasi Anda.
Token lengkap ditulis setelah Bearer: Authorization: Bearer 098afde9-…_jyDlM…. Kunci saja, tanpa <tokenId>_, ditolak dengan 403 unauthorized.
# data Anda (perlakukan token seperti kata sandi: variabel lingkungan, jangan di kode)
export NBT_API=https://server.nbt-host.com/api
export NBT_ORG=… # organisasi mitra Anda
export NBT_TOKEN=… # <tokenId>_<cheie>
curl -sS "$NBT_API/orgs/$NBT_ORG" -H "Authorization: Bearer $NBT_TOKEN"
# langganan Anda: sumber daya terpakai / total
curl -sS "$NBT_API/orgs/$NBT_ORG/subscriptions" -H "Authorization: Bearer $NBT_TOKEN"<?php
// nbt-api.php — PHP 7.4+, ekstensi cURL; mencoba ulang pada 429 / 503
function nbt_api(string $method, string $path, ?array $body = null): array
{
$url = (getenv('NBT_API') ?: 'https://server.nbt-host.com/api') . $path;
for ($try = 1; ; $try++) {
$ch = curl_init($url);
$headers = ['Authorization: Bearer ' . getenv('NBT_TOKEN'), 'Accept: application/json'];
if ($body !== null) {
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_TIMEOUT => 120,
]);
$raw = curl_exec($ch);
if ($raw === false) {
throw new RuntimeException('cURL: ' . curl_error($ch));
}
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$head = substr($raw, 0, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
$text = substr($raw, strlen($head));
if (($code === 429 || $code === 503) && $try < 4) {
preg_match('/^retry-after:\s*(\d+)/mi', $head, $m);
sleep((int) ($m[1] ?? 2 ** $try));
continue;
}
$data = json_decode($text, true);
if ($code >= 400) {
$msg = is_array($data) ? trim(($data['code'] ?? '') . ' ' . ($data['message'] ?? $data['detail'] ?? '')) : $text;
throw new RuntimeException("HTTP $code: $msg", $code);
}
return is_array($data) ? $data : ['value' => $data ?? $text];
}
}
$org = getenv('NBT_ORG'); // organisasi mitra Anda
print_r(nbt_api('GET', "/orgs/$org"));
print_r(nbt_api('GET', "/orgs/$org/subscriptions")); // langganan Anda: sumber daya terpakai / total// nbt-api.mjs — Node.js 18+ (fetch bawaan); mencoba ulang pada 429 / 503
const API = process.env.NBT_API ?? 'https://server.nbt-host.com/api';
export async function api(method, path, body) {
for (let attempt = 1; ; attempt++) {
const res = await fetch(API + path, {
method,
headers: {
Authorization: `Bearer ${process.env.NBT_TOKEN}`,
Accept: 'application/json',
...(body !== undefined && { 'Content-Type': 'application/json' }),
},
body: body !== undefined ? JSON.stringify(body) : undefined,
});
if ((res.status === 429 || res.status === 503) && attempt < 4) {
const wait = Number(res.headers.get('retry-after')) || 2 ** attempt;
await new Promise((r) => setTimeout(r, wait * 1000));
continue;
}
const text = await res.text();
let data;
try { data = text ? JSON.parse(text) : null; } catch { data = text; }
if (!res.ok) {
const msg = typeof data === 'object' && data ? `${data.code ?? ''} ${data.message ?? data.detail ?? ''}` : data;
throw Object.assign(new Error(`HTTP ${res.status}: ${String(msg).trim()}`), { status: res.status, body: data });
}
return data;
}
}
// node verifica.mjs — organisasi mitra Anda
// import { api } from './nbt-api.mjs';
const org = process.env.NBT_ORG;
console.log(await api('GET', `/orgs/${org}`));
console.log(await api('GET', `/orgs/${org}/subscriptions`)); // langganan Anda: sumber daya terpakai / total{"id":"5f0c…","parentId":"…","name":"…","status":"active","createdAt":"…",
"subscriptionsCount":1,"websitesCount":0,"locale":"…"}
{"items":[{"id":31,"planId":63,"planName":"nbthost_partener_30","subscriberId":"5f0c…","vendorId":"…",
"status":"active","planType":"shared","allowedPhpVersions":["php82","php83","php84"],"defaultPhpVersion":"php83",
"resources":[{"name":"customers","total":50,"usage":0},{"name":"websites","total":50,"usage":0}, …],
"allowances":[…],"selections":[],"friendlyName":"…"}],"total":1}Token melalui API
/orgs/{ORG}/access_tokensToken milik organisasi (array biasa, tanpa total; kunci tidak pernah ditampilkan)./orgs/{ORG}/access_tokensToken baru: {"roles":["SuperAdmin"],"friendlyName":"…","tokenExpires":"2027-01-01T00:00:00Z","allowedIps":["203.0.113.10"],"ipRestricted":true} → {"id","firstFive","unencryptedToken"}./orgs/{ORG}/access_tokens/{token_id}Ubah peran, masa berlaku, nama, atau alamat IP. Selalu kirim juga roles: tanpa itu, panel menjawab 500./orgs/{ORG}/access_tokens/{token_id}Pencabutan: token langsung berhenti berfungsi.curl -sS -X POST "$NBT_API/orgs/$NBT_ORG/access_tokens" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"roles":["SuperAdmin"],"friendlyName":"penagihan","tokenExpires":"2027-01-01T00:00:00Z","allowedIps":["203.0.113.10"],"ipRestricted":true}'{"id":"098afde9-…","firstFive":"jyDlM","unencryptedToken":"…"}
# token yang dipakai: <id>_<unencryptedToken>Rotasi dan pencabutan
- Buat token baru (di panel atau dengan
POST …/access_tokens) dengan peran yang sama. - Pasang di aplikasi Anda dan uji satu panggilan (
GET /orgs/{ORG}→ 200). - Hapus token lama:
DELETE /orgs/{ORG}/access_tokens/{token_id}atau dari panel.
Token yang bocor (di repositori git, log, atau email) segera dicabut lalu diganti. Masa berlaku bisa diperpanjang dengan PATCH tanpa membuat token baru.
Praktik yang baik
- Satu token per aplikasi dan per lingkungan (produksi, uji), dengan nama yang jelas: Anda bisa mencabut satu tanpa menghentikan yang lain.
- Pembatasan IP dan tanggal kedaluwarsa pada setiap token.
- Peran terkecil yang cukup:
Supportuntuk dasbor yang hanya membaca. - Simpan token di variabel lingkungan atau brankas, jangan pernah di kode, di browser, atau di aplikasi seluler: token dapat melihat semua pelanggan Anda.
- Jangan pernah mencatat header
Authorizationdi log, begitu juga responsGET /v2/domains/{id}/ssl(berisi kunci privat sertifikat).
URL dasar dan konvensi
- URL dasar:
https://server.nbt-host.com/api— semua path di bawah ditulis setelahnya.GET /version(tanpa token) mengembalikan versi sebagai teks:12.25.13. - Permintaan dengan body mengirim
Content-Type: application/json. Responsnya JSON, kecuali beberapa yang mengembalikan string (tautan SSO,/version). - Id: organisasi, situs, domain, login, dan anggota memakai uuid; paket, langganan, dan backup memakai bilangan bulat.
- Pembuatan mengembalikan
{"id": …}(201). Beberapa operasi mengembalikan body kosong (misalnya database, pemulihan, sertifikat). - Operasi yang memakan waktu (backup, pemulihan, sertifikat, instalasi WordPress) berjalan di latar belakang: baca statusnya dengan
GETyang sesuai setiap beberapa detik. - Penghapusan tanpa
forcebersifat “soft”: organisasi atau situs menjadideleteddan masih bisa dipulihkan selama beberapa hari jika Anda meminta kepada kami.
Paginasi
Daftar yang besar menerima offset dan limit dan mengembalikan {"items":[…],"total":N}. Tanpa limit Anda menerima seluruh daftar (terverifikasi: 70 situs dalam satu permintaan), jadi mintalah per halaman untuk daftar besar. Pengurutan: sortBy + sortOrder=asc|desc; pencarian: search.
| Daftar | Parameter |
|---|---|
GET /orgs/{ORG}/customers | offset, limit, sortBy=id|name|status|subscriptionsCount|websitesCount|createdAt, sortOrder, search, status=active|suspended|deleted, planId, recursive |
GET /orgs/{ORG}/websites | offset, limit, sortBy=domain|subscription|org|size|createdAt, sortOrder, search, recursion=directCustomers|infinite (termasuk situs pelanggan), planId, subscriptionId, status, isSuspended, showAliases, showDeleted |
GET /orgs/{ORG}/plans | offset, limit, sortBy=name, sortOrder |
Beberapa daftar kecil hanya mengembalikan {"items":[…]} tanpa total (domain sebuah situs, database, pengguna MySQL, aplikasi, backup), dan GET …/access_tokens mengembalikan array langsung.
# semua pelanggan, 100 per halaman
OFFSET=0; LIMIT=100
while :; do
PAGE=$(curl -sS "$NBT_API/orgs/$NBT_ORG/customers?offset=$OFFSET&limit=$LIMIT&sortBy=name&sortOrder=asc" \
-H "Authorization: Bearer $NBT_TOKEN")
echo "$PAGE" | jq -r '.items[] | [.id, .name, .status, .websitesCount] | @tsv'
OFFSET=$((OFFSET + LIMIT))
[ "$OFFSET" -ge "$(echo "$PAGE" | jq .total)" ] && break
done<?php
require __DIR__ . '/nbt-api.php';
$org = getenv('NBT_ORG');
// semua pelanggan, 100 per halaman
$offset = 0; $limit = 100;
do {
$page = nbt_api('GET', "/orgs/$org/customers?offset=$offset&limit=$limit&sortBy=name&sortOrder=asc");
foreach ($page['items'] as $c) {
printf("%s\t%s\t%s\t%d\n", $c['id'], $c['name'], $c['status'], $c['websitesCount']);
}
$offset += $limit;
} while ($offset < $page['total']);import { api } from './nbt-api.mjs';
const org = process.env.NBT_ORG;
// semua pelanggan, 100 per halaman
async function* customers(limit = 100) {
for (let offset = 0; ; offset += limit) {
const page = await api('GET', `/orgs/${org}/customers?offset=${offset}&limit=${limit}&sortBy=name&sortOrder=asc`);
yield* page.items;
if (offset + limit >= page.total) return;
}
}
for await (const c of customers()) console.log(c.id, c.name, c.status, c.websitesCount);{"items":[{"id":"fea953a8-…","parentId":"5f0c…","name":"PT Klien Contoh","status":"active",
"createdAt":"2026-10-21T09:14:03Z","subscriptionsCount":1,"websitesCount":1,"locale":"…"}, …],
"total":27}Pelanggan baru dengan situs dan email, dalam 5 panggilan
Alur yang diotomatiskan oleh sebagian besar mitra. Anda memerlukan paket pelanggan (Paket untuk pelanggan): PLAN_ID adalah id-nya dari GET /orgs/$NBT_ORG/plans. Contoh memakai jq untuk curl, dan fungsi bantu dari Autentikasi untuk PHP dan Node.js.
# 1. pelanggan (organisasi baru di bawah organisasi Anda) — simpan id-nya: POST yang diulang membuat pelanggan lain
CLIENT=$(curl -sS -X POST "$NBT_API/orgs/$NBT_ORG/customers" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"PT Klien Contoh"}' | jq -r .id)
# 2. langganannya ke salah satu paket Anda (PLAN_ID: GET /orgs/$NBT_ORG/plans)
SUB=$(curl -sS -X POST "$NBT_API/orgs/$NBT_ORG/customers/$CLIENT/subscriptions" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d "{\"planId\":$PLAN_ID}" | jq -r .id)
# 3. situs, dengan domain dan versi PHP (yang diizinkan paket)
SITE=$(curl -sS -X POST "$NBT_API/orgs/$CLIENT/websites" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d "{\"domain\":\"toko-klien.co.id\",\"subscriptionId\":$SUB,\"phpVersion\":\"php83\"}" | jq -r .id)
# 4. id domain utama (untuk email, DNS, SSL)
DOMAIN_ID=$(curl -sS "$NBT_API/orgs/$CLIENT/websites/$SITE" \
-H "Authorization: Bearer $NBT_TOKEN" | jq -r .domain.id)
# 5. kotak surat (kata sandi: min. 10 karakter, huruf besar dan kecil, angka, simbol; kuota dalam byte)
curl -sS -X POST "$NBT_API/orgs/$CLIENT/websites/$SITE/domains/$DOMAIN_ID/emails" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d "{\"username\":\"contact\",\"mailboxPassword\":\"$MAIL_PASS\",\"quota\":1073741824}"<?php
require __DIR__ . '/nbt-api.php';
$org = getenv('NBT_ORG');
$planId = (int) getenv('PLAN_ID');
// 1. pelanggan (organisasi baru di bawah organisasi Anda) — simpan id-nya: POST yang diulang membuat pelanggan lain
$client = nbt_api('POST', "/orgs/$org/customers", ['name' => 'PT Klien Contoh'])['id'];
// 2. langganannya ke salah satu paket Anda (PLAN_ID: GET /orgs/$NBT_ORG/plans)
$sub = nbt_api('POST', "/orgs/$org/customers/$client/subscriptions", ['planId' => $planId])['id'];
// 3. situs, dengan domain dan versi PHP (yang diizinkan paket)
$site = nbt_api('POST', "/orgs/$client/websites", [
'domain' => 'toko-klien.co.id', 'subscriptionId' => $sub, 'phpVersion' => 'php83',
])['id'];
// 4. id domain utama (untuk email, DNS, SSL)
$domainId = nbt_api('GET', "/orgs/$client/websites/$site")['domain']['id'];
// 5. kotak surat (kata sandi: min. 10 karakter, huruf besar dan kecil, angka, simbol; kuota dalam byte)
nbt_api('POST', "/orgs/$client/websites/$site/domains/$domainId/emails", [
'username' => 'contact', 'mailboxPassword' => getenv('MAIL_PASS'), 'quota' => 1073741824,
]);
echo "client=$client subscription=$sub website=$site domain=$domainId\n";import { api } from './nbt-api.mjs';
const org = process.env.NBT_ORG;
const planId = Number(process.env.PLAN_ID);
// 1. pelanggan (organisasi baru di bawah organisasi Anda) — simpan id-nya: POST yang diulang membuat pelanggan lain
const { id: client } = await api('POST', `/orgs/${org}/customers`, { name: 'PT Klien Contoh' });
// 2. langganannya ke salah satu paket Anda (PLAN_ID: GET /orgs/$NBT_ORG/plans)
const { id: sub } = await api('POST', `/orgs/${org}/customers/${client}/subscriptions`, { planId });
// 3. situs, dengan domain dan versi PHP (yang diizinkan paket)
const { id: site } = await api('POST', `/orgs/${client}/websites`, {
domain: 'toko-klien.co.id', subscriptionId: sub, phpVersion: 'php83',
});
// 4. id domain utama (untuk email, DNS, SSL)
const { domain } = await api('GET', `/orgs/${client}/websites/${site}`);
// 5. kotak surat (kata sandi: min. 10 karakter, huruf besar dan kecil, angka, simbol; kuota dalam byte)
await api('POST', `/orgs/${client}/websites/${site}/domains/${domain.id}/emails`, {
username: 'contact', mailboxPassword: process.env.MAIL_PASS, quota: 1073741824,
});
console.log({ client, sub, site, domainId: domain.id });{"id":"fea953a8-…"} ← 1. POST /customers (uuid)
{"id":31} ← 2. POST /subscriptions (int)
{"id":"3d064861-…"} ← 3. POST /websites (uuid)
{"id":"3d064861-…","domain":{"id":"9b1e…","domain":"toko-klien.co.id","kind":"primary",…},"status":"active",
"phpVersion":"php83","subscriptionId":31,…} ← 4. GET /websites/{id}
{"id":"…"} ← 5. POST /emailsSitus mendapatkan zona DNS di name server kami (atau milik Anda, jika sudah diatur), versi PHP yang dipilih, dan batas memori serta CPU dari paket Anda. Sertifikat Let's Encrypt diterbitkan otomatis setelah domain mengarah ke server (SSL). Agar pelanggan bisa masuk ke panel: Akses pelanggan.
Panggilan ini tidak idempoten: POST /customers yang diulang membuat pelanggan lain, yang memakai satu slot kuota Anda. Simpan setiap id segera; saat mencoba ulang, cari dulu (GET /orgs/$NBT_ORG/customers?search=…, GET /orgs/$CLIENT/websites) lalu lanjutkan dari langkah yang belum selesai.
Pelanggan
/orgs/{ORG}/customersPelanggan baru: {"name":"PT Klien Contoh"} → {"id":"uuid"}. Memakai satu slot kuota customers sejak dibuat./orgs/{CLIENT}Data pelanggan: name, status, parentId, subscriptionsCount, websitesCount./orgs/{CLIENT}Ganti nama: {"name":"PT Nama Baru"}./orgs/{CLIENT}/subscriptionsLangganan pelanggan (dengan pemakaian sumber daya)./orgs/{CLIENT}/subscriptions/{subscription_id}Tangguhkan / aktifkan kembali: {"isSuspended":true|false}./orgs/{CLIENT}Penghapusan “soft” pelanggan, beserta situs-situsnya.curl -sS "$NBT_API/orgs/$CLIENT" -H "Authorization: Bearer $NBT_TOKEN"{"id":"fea953a8-…","parentId":"5f0c…","name":"PT Klien Contoh","status":"active",
"createdAt":"2026-10-21T09:14:03Z","subscriptionsCount":1,"websitesCount":1,"locale":"id"}Penangguhan dan pengaktifan kembali
Yang ditangguhkan adalah langganan pelanggan. Selama ditangguhkan, situs pelanggan menjawab 404 dan emailnya berhenti berfungsi; datanya tetap ada. Pelanggan yang Anda tangguhkan tetap ditangguhkan meskipun kami mengaktifkan kembali paket Anda (misalnya setelah pembayaran terlambat).
# langganan pelanggan
SUB=$(curl -sS "$NBT_API/orgs/$CLIENT/subscriptions" -H "Authorization: Bearer $NBT_TOKEN" | jq -r '.items[0].id')
# tangguhkan (situs pelanggan menjawab 404) / aktifkan kembali
curl -sS -X PATCH "$NBT_API/orgs/$CLIENT/subscriptions/$SUB" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' -d '{"isSuspended":true}'
curl -sS -X PATCH "$NBT_API/orgs/$CLIENT/subscriptions/$SUB" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' -d '{"isSuspended":false}' <?php
require __DIR__ . '/nbt-api.php';
$client = getenv('CLIENT');
// langganan pelanggan
$sub = nbt_api('GET', "/orgs/$client/subscriptions")['items'][0]['id'];
// tangguhkan (situs pelanggan menjawab 404) / aktifkan kembali
nbt_api('PATCH', "/orgs/$client/subscriptions/$sub", ['isSuspended' => true]);
nbt_api('PATCH', "/orgs/$client/subscriptions/$sub", ['isSuspended' => false]);import { api } from './nbt-api.mjs';
const client = process.env.CLIENT;
// langganan pelanggan
const { items: [sub] } = await api('GET', `/orgs/${client}/subscriptions`);
// tangguhkan (situs pelanggan menjawab 404) / aktifkan kembali
await api('PATCH', `/orgs/${client}/subscriptions/${sub.id}`, { isSuspended: true });
await api('PATCH', `/orgs/${client}/subscriptions/${sub.id}`, { isSuspended: false });Penghapusan
Urutannya: backup yang tidak lagi diperlukan, situs, langganan, lalu organisasi. Penghapusan permanen (?force=true) khusus untuk administrator platform: token Anda menerima 403 only_mo_allowed. Kami melakukannya atas permintaan; sampai saat itu pelanggan yang dihapus “soft” masih bisa dipulihkan.
curl -sS "$NBT_API/orgs/$CLIENT/websites/$SITE/backups" -H "Authorization: Bearer $NBT_TOKEN" # backup yang ada
curl -sS -X DELETE "$NBT_API/orgs/$CLIENT/websites/$SITE" -H "Authorization: Bearer $NBT_TOKEN"
curl -sS -X DELETE "$NBT_API/orgs/$CLIENT/subscriptions/$SUB" -H "Authorization: Bearer $NBT_TOKEN"
curl -sS -X DELETE "$NBT_API/orgs/$CLIENT" -H "Authorization: Bearer $NBT_TOKEN"Paket untuk pelanggan
Anda yang menentukan apa yang didapat setiap pelanggan: Anda membuat paket dari batas Anda sendiri dan menjualnya dengan harga Anda. Paket tidak boleh meminta lebih dari yang Anda miliki (403 resource_out_of_quota), juga tidak boleh berisi fitur yang tidak ada di paket Anda (403 non_existent_allowance).
/orgs/{ORG}/plansPaket Anda (dengan paginasi, sortBy=name)./orgs/{ORG}/plans/{plan_id}Satu paket, dengan resources, allowances, allowedPhpVersions./orgs/{ORG}/plansPaket baru → {"id":17}./orgs/{ORG}/plans/{plan_id}Nama paket: {"name":"…"}./orgs/{ORG}/plans/{plan_id}/resources/{name}Satu batas: {"name":"websites","total":3}./orgs/{ORG}/plans/{plan_id}/resourcesSumber daya yang belum ada di paket./orgs/{ORG}/plans/{plan_id}/allowancesTambah fitur: [{"name":"featureCronjobs"}]./orgs/{ORG}/plans/{plan_id}/allowances/{name}Hapus fitur./orgs/{ORG}/plans/{plan_id}Hapus paket, hanya jika tidak ada langganan lagi. Langganan yang Anda hapus (tanpa force) masih menahannya: 403 unmigrated_subscriptions. Pindahkan pelanggan ke paket lain dulu, atau minta kami menghapusnya permanen.curl -sS -X POST "$NBT_API/orgs/$NBT_ORG/plans" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"Situs profil usaha",
"resources":[{"name":"websites","total":1},{"name":"diskspace","total":5368709120},
{"name":"mailboxes","total":5},{"name":"mysqlDbs","total":2},
{"name":"subdomains","total":5},{"name":"domainAliases","total":2},{"name":"forwarders"},{"name":"transfer"}],
"allowances":[{"name":"featureLetsEncrypt"},{"name":"backupsAllowAutomatic"},{"name":"featureDNSEditor"},{"name":"wptoolkit"}],
"selections":[],
"allowedPhpVersions":["php83","php84"],"defaultPhpVersion":"php83"}'{"id":17}- Sumber daya (
name):websites,diskspace(byte),mailboxes,mysqlDbs,subdomains,domainAliases,ftpUsers,forwarders,transfer,pageViews. Sumber daya tanpatotalberarti tidak terbatas, tetapi hanya jika paket Anda juga tidak membatasinya. Sumber daya yang tidak dicantumkan berarti 0. - Fitur (
allowances), yang juga dimiliki paket Anda:featureLetsEncrypt,featureSelfInstallSSL,featureDNSEditor,featureDNSAutoConfigure,featureCronjobs,featurePhpEditor,featureWebsiteClone,featureWebsiteCaching,featureCPanelMigrate,backupsAllowAutomatic,backupsAllowManual,backupsAllowSelfRestore,applicationsSoftwareInstaller,wptoolkitdanwptoolkit…(manajer, Shield, penyamaran halaman login). allowedPhpVersionswajib dan tidak boleh kosong, dariphp82,php83,php84. Tanpa itu:400 invalid_argument“Allowed PHP versions cannot be empty since the parent package has restrictions”.mysqlDbs: minimal satu database kosong jika pelanggan memasang WordPress (instalasi membuat database sendiri).- Batas diubah satu per satu, dengan
PUT …/resources/{name}.PATCHpada paket hanya mengubah namanya. - Fitur hanya membatasi apa yang bisa dilakukan pelanggan di panelnya; token mitra Anda tetap bisa membuat backup atau memasang aplikasi meskipun paketnya tidak memiliki fitur tersebut.
Langganan
/orgs/{ORG}/subscriptionsLangganan mitra Anda: kuota dan pemakaiannya (resources[].usage / total)./orgs/{ORG}/customers/{CLIENT}/subscriptionsLanggankan pelanggan ke sebuah paket: {"planId":17} → {"id":31}./orgs/{ORG}/customers/{CLIENT}/subscriptionsLangganan pelanggan ke paket-paket Anda./orgs/{CLIENT}/subscriptions/{subscription_id}Satu langganan, dengan sumber dayanya./orgs/{CLIENT}/subscriptions/{subscription_id}{"isSuspended":true}, {"planId":18} (ganti paket) atau {"friendlyName":"…"}./orgs/{CLIENT}/subscriptions/{subscription_id}/calculate-resource-usageHitung ulang pemakaian (misalnya ruang disk)./orgs/{CLIENT}/subscriptions/{subscription_id}/bandwidthLalu lintas bulan berjalan./orgs/{CLIENT}/subscriptions/{subscription_id}Penghapusan “soft” langganan dan situs di dalamnya.curl -sS "$NBT_API/orgs/$CLIENT/subscriptions" -H "Authorization: Bearer $NBT_TOKEN"{"items":[{"id":31,"planId":17,"planName":"Situs profil usaha","subscriberId":"fea953a8-…","vendorId":"5f0c…",
"status":"active","planType":"shared","friendlyName":"…","allowedPhpVersions":["php83","php84"],
"defaultPhpVersion":"php83","redisAllowed":false,"persistentAppsAllowed":false,"allowedApps":null,
"resources":[{"name":"websites","total":1,"usage":1},{"name":"diskspace","total":5368709120,"usage":81920}, …],
"allowances":[{"name":"featureLetsEncrypt"}, …],"selections":[]}],"total":1}diskspace dalam byte. Sumber daya tanpa total berarti tidak terbatas.
Situs dan domain
/orgs/{CLIENT}/websitesSitus pelanggan (dengan paginasi). Dari organisasi Anda dengan ?recursion=infinite: semua situs semua pelanggan, dengan orgId./orgs/{CLIENT}/websitesSitus baru: {"domain":"toko-klien.co.id","subscriptionId":31,"phpVersion":"php83"} → {"id":"uuid"}./orgs/{CLIENT}/websites/{website_id}Situs: domain, aliases, subdomains, status, phpVersion, size, unixUser, IP server./orgs/{CLIENT}/websites/{website_id}{"phpVersion":"php84"}, {"isSuspended":true} (hanya situs ini)./orgs/{CLIENT}/websites/{website_id}Penghapusan “soft” situs./orgs/{CLIENT}/websites/{website_id}/domainsDomain situs: domainId, domain, mappingKind, documentRoot./orgs/{CLIENT}/websites/{website_id}/domainsAlias atau subdomain: {"domain":"…","kind":"alias"|"subdomain","documentRoot":"…"} → {"id"}./orgs/{CLIENT}/websites/{website_id}/domains/primaryJadikan domain lain sebagai domain utama: {"domainId":"…"}./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}Ubah documentRoot./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}Hapus alias / subdomain (beserta zona dan kotak suratnya)./orgs/{CLIENT}/websites/{website_id}/cgroup_limitsBatas memori dan CPU situs (hanya baca)./v2/websites/{website_id}/restart_phpMulai ulang PHP situs./orgs/{ORG}/domains/checkPeriksa apakah domain sudah ada di server: {"domain":"…"}.curl -sS "$NBT_API/orgs/$CLIENT/websites?limit=20&offset=0&sortBy=domain" -H "Authorization: Bearer $NBT_TOKEN"{"items":[{"id":"3d064861-…","domain":{"id":"9b1e…","domain":"toko-klien.co.id","documentRoot":"public_html",
"kind":"primary","cloudflareStatus":"…"},"aliases":[],"subdomains":[],"subscriptionId":31,"planId":17,
"plan":"Situs profil usaha","status":"active","size":81920,"orgId":"fea953a8-…","kind":"normal",
"createdAt":"…","phpVersion":"php83","appServerName":"…","emailServerName":"…", …}],"total":1}curl -sS -X POST "$NBT_API/orgs/$CLIENT/websites/$SITE/domains" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"domain":"blog.toko-klien.co.id","kind":"subdomain","documentRoot":"public_html/blog"}'phpVersion: salah satu versi yang diizinkan paket pelanggan (jika tidak,400 invalid_argument). Tanpa itu, situs memakaidefaultPhpVersionpaket.- Alias dan subdomain dihitung pada
domainAliasesdansubdomains, bukan sebagai situs. Domain addon tidak termasuk. - Domain yang sudah ada di server di organisasi lain, atau subdomainnya (misalnya
*.nbt-host.ro), ditolak:403“Unable to create website outside of the org”.
DNS
Setiap domain memiliki zonanya sendiri di name server kami (ns1.nbt-host.ro / ns2.nbt-host.ro, atau milik Anda, lihat Branding). Zona diakses melalui situs dan domain_id.
/orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/dns-zoneZona: origin, soa, records[] (id, kind, name, value, proxy)./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/dns-zone/recordsRecord baru → {"id"}./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/dns-zone/records/{record_id}Ubah value, ttl, name./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/dns-zone/records/{record_id}Hapus record./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/dns-zoneNilai SOA./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/dns-statusApakah domain sudah mengarah ke kami./orgs/{CLIENT}/domainsDomain organisasi, dengan dkim, spf, localRemote.curl -sS "$NBT_API/orgs/$CLIENT/websites/$SITE/domains/$DOMAIN_ID/dns-zone" -H "Authorization: Bearer $NBT_TOKEN"{"origin":"toko-klien.co.id.","soa":{"nameServer":"ns1.nbt-host.ro.","adminEmail":"…","refresh":10800,
"retry":3600,"expire":604800,"ttl":3600},
"records":[{"id":"7a1c…","kind":"A","name":"@","value":"185.230.138.193","proxy":false},
{"id":"…","kind":"CNAME","name":"www","value":"toko-klien.co.id.","proxy":false}, …]}curl -sS -X POST "$NBT_API/orgs/$CLIENT/websites/$SITE/domains/$DOMAIN_ID/dns-zone/records" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"kind":"TXT","name":"@","value":"google-site-verification=…","ttl":3600}'Jenis record (kind): A, AAAA, CNAME, MX, TXT, SRV, CAA, NS, SPF, PTR, DS. name relatif terhadap zona (@ untuk root, www, *.dev untuk wildcard).
SSL (Let's Encrypt)
Sertifikat Let's Encrypt diterbitkan dan diperpanjang otomatis untuk setiap domain situs setelah domain mengarah ke server. Mintalah secara manual hanya setelah perubahan DNS, atau jika Anda ingin segera mendapatkannya.
/v2/domains/{domain_id}/letsencrypt_preflightPeriksa apakah bisa diterbitkan: {"canIssue":true} atau {"canIssue":false,"error":"…"}./v2/domains/{domain_id}/letsencryptTerbitkan (dan pasang) sertifikat; butuh beberapa puluh detik./v2/domains/{domain_id}/letsencrypt_mailSertifikat untuk mail.<domain>./v2/domains/{domain_id}/sslSertifikat terpasang: cn, issuer, issued, expires, sans, forceHttps (dan kunci privat — jangan dicatat di log)./v2/domains/{domain_id}/ssl/force_sslPengalihan HTTP → HTTPS: body true atau false./v2/domains/{domain_id}/sslSertifikat Anda sendiri (cert, kunci, rantai) sebagai ganti Let's Encrypt.curl -sS -X POST "$NBT_API/v2/domains/$DOMAIN_ID/letsencrypt_preflight" -H "Authorization: Bearer $NBT_TOKEN"
curl -sS -X POST "$NBT_API/v2/domains/$DOMAIN_ID/letsencrypt" -H "Authorization: Bearer $NBT_TOKEN"
curl -sS -X PUT "$NBT_API/v2/domains/$DOMAIN_ID/ssl/force_ssl" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' -d 'true'
# statusnya, tanpa kunci privat:
curl -sS "$NBT_API/v2/domains/$DOMAIN_ID/ssl" -H "Authorization: Bearer $NBT_TOKEN" | jq '{cn, issuer, expires, sans, forceHttps}'{"cn":"toko-klien.co.id","issuer":"…Let's Encrypt…","expires":"2027-01-19T08:12:44Z",
"sans":["toko-klien.co.id","www.toko-klien.co.id"],"forceHttps":true}Kotak surat berada di domain sebuah situs. Pembuatannya memakai domain_id; operasi lainnya memakai alamat lengkap (kontak@toko-klien.co.id, di-encode di URL menjadi kontak%40toko-klien.co.id).
/orgs/{CLIENT}/websites/{website_id}/emailsAlamat-alamat situs: address, hasMailbox, quota {total, usage}, forwardersCount, aliases./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/emailsKotak surat: {"username":"kontak","mailboxPassword":"…","quota":1073741824}. Hanya penerusan: {"username":"penjualan","forwarders":["budi@gmail.com"]}./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}Satu alamat, dengan forwarders, aliases, blacklist, whitelist./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}Kata sandi (mailboxPassword), quota, forwarders, aliases, isCatchAll, hasMailbox./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}Hapus alamat (beserta pesan di kotak suratnya)./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}/autoresponderBalasan otomatis (null jika tidak ada)./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}/autoresponderAktifkan balasan otomatis: {"enabled":true,"subject":"…","body":"…","startDate":"2026-12-20T00:00:00Z","endDate":"2027-01-05T00:00:00Z"}./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}/autoresponderMatikan balasan otomatis./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}/ssoMasuk langsung ke webmail (Roundcube), tanpa kata sandi: jawabannya pengalihan (307) ke webmail./orgs/{CLIENT}/websites/{website_id}/emails/{email_address}/client-confPengaturan IMAP / SMTP untuk Outlook, Thunderbird, ponsel./websites/{website_id}/domains/{domain_name}/email-authDKIM: {"dkim":true,"dkimPublicKey":"…"}./websites/{website_id}/domains/{domain_name}/email-authAktifkan / matikan DKIM: {"dkim":true}./websites/{website_id}/domains/{domain_name}/email-auth/validatePeriksa DKIM dan SPF di DNS./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/local_remote{"localRemote":"local"}: email domain di-hosting di tempat kami./orgs/{CLIENT}/websites/{website_id}/domains/{domain_id}/local_remote{"localRemote":"remote"} jika email ada di penyedia lain (Google Workspace, Microsoft 365): server berhenti mengirimkan pesan domain itu secara lokal.ADDR=kontak%40toko-klien.co.id
curl -sS -X PATCH "$NBT_API/orgs/$CLIENT/websites/$SITE/emails/$ADDR" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"mailboxPassword":"'"$SANDI_BARU"'","forwarders":["budi.santoso@gmail.com"]}'curl -sS "$NBT_API/orgs/$CLIENT/websites/$SITE/emails/$ADDR" -H "Authorization: Bearer $NBT_TOKEN"{"websiteId":"3d064861-…","address":"kontak@toko-klien.co.id","mailboxName":"…","aliases":[],
"forwarders":[],"status":"active","quota":{"total":1073741824,"usage":4524},"spamDelivery":null,
"blacklist":[],"whitelist":[],"autorespondersCount":0,"hasMailbox":true,"isCatchAll":false,"ssoAvailable":true}- Kata sandi (kotak surat dan login): minimal 10 karakter, dengan huruf besar dan kecil, angka, dan simbol. Kata sandi sederhana:
400 invalid_argument“Password is not complex enough”. quotadalam byte (1073741824 = 1 GiB). Setiap kotak surat dihitung padamailboxespaket.- DKIM nonaktif secara default pada domain baru: aktifkan dengan
PUT …/email-authsetelah membuat kotak surat, lalu periksa dengan…/email-auth/validate. Jika DNS di-hosting di tempat lain, tambahkan record TXT daridkimPublicKeydi sana. - Server memiliki batas pengiriman per jam (untuk mencegah spam); email massal (newsletter) sebaiknya lewat layanan khusus.
Database MySQL
/orgs/{CLIENT}/websites/{website_id}/mysql-dbsDatabase situs./orgs/{CLIENT}/websites/{website_id}/mysql-dbsDatabase baru: {"name":"toko"}. Panel menambahkan sendiri prefiks situs (misalnya klien_1_toko): baca nama akhirnya dengan GET./orgs/{CLIENT}/websites/{website_id}/mysql-dbs/{db_name}Hapus database./orgs/{CLIENT}/websites/{website_id}/mysql-usersPengguna, dengan grants dan accessHosts./orgs/{CLIENT}/websites/{website_id}/mysql-usersPengguna baru: {"username":"app","password":"…"}./orgs/{CLIENT}/websites/{website_id}/mysql-users/{username}/privilegesHak pada satu database: {"dbName":"klien_1_toko","grants":["all"]} ([] mencabutnya)./orgs/{CLIENT}/websites/{website_id}/mysql-users/{username}Kata sandi pengguna./orgs/{CLIENT}/websites/{website_id}/mysql-users/{username}/access-hostsHost yang boleh dipakai untuk terhubung./orgs/{CLIENT}/websites/{website_id}/mysql-users/{username}Hapus pengguna./orgs/{CLIENT}/websites/{website_id}/mysql-dbs/{db_name}/ssoMasuk langsung ke phpMyAdmin pada database tersebut. Saat ini menjawab 404 not_found “phpMyAdmin domain not configured”: buka phpMyAdmin dari panel.curl -sS "$NBT_API/orgs/$CLIENT/websites/$SITE/mysql-users" -H "Authorization: Bearer $NBT_TOKEN"{"items":[{"username":"klien_1_app","accessHosts":["localhost","…"],"authPlugin":"…",
"grants":{"klien_1_toko":["all"]},"createdAt":"…","isEphemeral":false}]}PostgreSQL tidak termasuk dalam paket mitra. Database dihitung pada mysqlDbs.
Backup dan pemulihan
Situs memiliki backup otomatis (harian) yang kami buat di server backup. Melalui API Anda bisa melihat daftarnya, membuat backup sesuai permintaan, dan memulihkan file, database, serta kotak surat.
/orgs/{CLIENT}/websites/{website_id}/backupsDaftar backup: id, startedAt, finishedAt, kind (automatic / manual), size, mysqlDbsCount, emailsCount, statusnya./orgs/{CLIENT}/websites/{website_id}/backups?includeEmails=trueBackup sesuai permintaan (body {} atau {"description":"sebelum pembaruan"})./orgs/{CLIENT}/websites/{website_id}/backups/{backup_id}Satu backup (404 not_found “Restore point … not found” jika tidak ada)./orgs/{CLIENT}/websites/{website_id}/status/backupBackup yang sedang berjalan, jika ada (null jika tidak)./orgs/{CLIENT}/websites/{website_id}/backups/{backup_id}Pemulihan, dengan opsi di body./orgs/{CLIENT}/websites/{website_id}/backups/{backup_id}/restore_statusStatus pemulihan./orgs/{CLIENT}/websites/{website_id}/backups/{backup_id}/directory_treeFile di dalam backup (untuk pemulihan sebagian)./orgs/{CLIENT}/websites/{website_id}/backups/{backup_id}Hapus backup. Saat ini menjawab 404 not_found “remote_storage” di platform kami: backup terhapus otomatis setelah masa simpan; jika satu backup harus dihapus, hubungi kami.curl -sS -X POST "$NBT_API/orgs/$CLIENT/websites/$SITE/backups?includeEmails=true" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' -d '{"description":"sebelum pembaruan"}'
curl -sS -X PUT "$NBT_API/orgs/$CLIENT/websites/$SITE/backups/$BACKUP_ID" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"restoreFiles":true,"restoreAllEmails":true,"restoreDatabases":["klien_1_toko"]}'- Body pemulihan:
restoreFiles(direktori home situs),restoreOnlyFiles(hanya path tertentu),restoreDatabases(tidak ada = semua database di backup;[]= tidak ada),restoreEmailsataurestoreAllEmails. Selalu kirimkan secara eksplisit. - Pemulihan mengembalikan keadaan situs yang masih ada; tidak membuat ulang situs, database, atau kotak surat yang dihapus lewat API. Untuk situs yang terhapus, hubungi kami.
- Backup memakai ruang di server backup, bukan penyimpanan paket Anda.
WordPress
/orgs/{CLIENT}/websites/{website_id}/appsPasang: {"app":"wordpress","path":"","adminUsername":"…","adminPassword":"…","adminEmail":"…"} → {"id"}./orgs/{CLIENT}/websites/{website_id}/appsAplikasi situs: id, app, version, path./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/infoversion, site_url, plugin_count, user_count, has_woocommerce./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/versionVersi, dibaca secara langsung./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/versionPerbarui WordPress ke versi terbaru (tanpa body; jika sudah terbaru, 200 tanpa perubahan)./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/usersPengguna WordPress: id, login, email./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/users/{user_id}/ssoTautan masuk langsung ke wp-admin./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/pluginsPlugin./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/pluginsPasang plugin./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/plugins/{plugin}/versionPerbarui plugin./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}/wordpress/themesTema: name, status, version, update, autoUpdate./v2/apps/{app_id}/wordpress/maintenance-modeMode pemeliharaan./orgs/{CLIENT}/websites/{website_id}/apps/{app_id}Copot pemasangan (backup situs dibuat terlebih dahulu).curl -sS -X POST "$NBT_API/orgs/$CLIENT/websites/$SITE/apps" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"app":"wordpress","path":"","adminUsername":"admin-toko","adminPassword":"'"$WP_PASS"'","adminEmail":"budi@toko-klien.co.id"}'
curl -sS "$NBT_API/orgs/$CLIENT/websites/$SITE/apps/$APP/wordpress/info" -H "Authorization: Bearer $NBT_TOKEN"{"id":"c0ffee12-…"}
{"version":"6.8.3","site_url":"https://toko-klien.co.id","plugin_count":3,"user_count":1,"has_woocommerce":false}Instalasi mengaktifkan PHP di situs dan membuat database sendiri (paket pelanggan memerlukan slot mysqlDbs yang kosong). Prosesnya sekitar satu menit; sebelum selesai, …/wordpress/info bisa mengembalikan error.
Akses pelanggan ke panel dan SSO
Pasang dulu panel di domain Anda sendiri (Branding). Pelanggan Anda berada di realm Anda dan masuk di domain panel Anda (misalnya https://panel.agensi-anda.co.id), bukan di server.nbt-host.com.
Cara 1: Anda yang membuat akunnya (tanpa email)
# login pelanggan, di realm Anda (orgId = organisasi PELANGGAN)
LOGIN=$(curl -sS -X POST "$NBT_API/logins?orgId=$CLIENT" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d "{\"email\":\"budi@toko-klien.co.id\",\"name\":\"Budi Santoso\",\"password\":\"$LOGIN_PASS\"}" | jq -r .id)
# anggota dengan peran Owner di organisasi pelanggan
MEMBER=$(curl -sS -X POST "$NBT_API/orgs/$CLIENT/members" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d "{\"loginId\":\"$LOGIN\",\"roles\":[\"Owner\"]}" | jq -r .id)
# tautan masuk sekali pakai berumur pendek, di domain panel Anda
curl -sS "$NBT_API/orgs/$CLIENT/members/$MEMBER/sso" -H "Authorization: Bearer $NBT_TOKEN"<?php
require __DIR__ . '/nbt-api.php';
$client = getenv('CLIENT');
// login pelanggan, di realm Anda (orgId = organisasi PELANGGAN)
$login = nbt_api('POST', "/logins?orgId=$client", [
'email' => 'budi@toko-klien.co.id', 'name' => 'Budi Santoso', 'password' => getenv('LOGIN_PASS'),
])['id'];
// anggota dengan peran Owner di organisasi pelanggan
$member = nbt_api('POST', "/orgs/$client/members", ['loginId' => $login, 'roles' => ['Owner']])['id'];
// tautan masuk sekali pakai berumur pendek, di domain panel Anda
$link = nbt_api('GET', "/orgs/$client/members/$member/sso")['value'];
header('Location: ' . $link);import { api } from './nbt-api.mjs';
const client = process.env.CLIENT;
// login pelanggan, di realm Anda (orgId = organisasi PELANGGAN)
const { id: loginId } = await api('POST', `/logins?orgId=${client}`, {
email: 'budi@toko-klien.co.id', name: 'Budi Santoso', password: process.env.LOGIN_PASS,
});
// anggota dengan peran Owner di organisasi pelanggan
const { id: member } = await api('POST', `/orgs/${client}/members`, { loginId, roles: ['Owner'] });
// tautan masuk sekali pakai berumur pendek, di domain panel Anda
const link = await api('GET', `/orgs/${client}/members/${member}/sso`);
console.log(link);{"id":"a5a86df8-…"} ← POST /logins
{"id":"0c7d…"} ← POST /members
"https://panel.agensi-anda.co.id/api/login/sessions/sso?otp=…" ← GET /ssoCara 2: undangan lewat email
curl -sS -X POST "$NBT_API/orgs/$CLIENT/invites" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' \
-d '{"email":"budi@toko-klien.co.id","name":"Budi Santoso","roles":["SuperAdmin"]}'Panel mengirim email dari alamat yang diatur di Pengaturan → Branding, dengan tautan di domain panel Anda; pelanggan memilih kata sandinya sendiri. Dengan "sendEmail":false tidak ada email yang dikirim dan tautannya dikembalikan dalam respons, untuk Anda kirimkan sendiri. Peran Owner tidak dapat diberikan lewat undangan (400): buat pemilik dengan cara 1.
/orgs/{CLIENT}/membersAnggota organisasi (dan undangan yang belum diterima)./logins?orgId={CLIENT}Login baru di realm Anda: {"email","name","password"} → {"id"}./orgs/{CLIENT}/membersAnggota: {"loginId":"…","roles":["Owner"]}./orgs/{CLIENT}/members/{member_id}Peran anggota./orgs/{CLIENT}/members/{member_id}Cabut akses./v2/logins/{login_id}/passwordKata sandi baru untuk sebuah login: {"newPassword":"…"}./orgs/{CLIENT}/members/{member_id}/ssoTautan masuk sekali pakai (SSO) berumur pendek, untuk tombol “Masuk ke panel” di aplikasi Anda./v2/orgs/{ORG}/customers/loginsLogin pelanggan Anda./orgs/{CLIENT}/invitesUndangan lewat email (lihat di atas).Peran: Owner (semua hal di organisasi pelanggan), SuperAdmin, Sysadmin, Support, Business, SiteAccess (hanya situs tertentu). Tautan SSO hanya bisa dipakai sekali dan cepat kedaluwarsa: mintalah tepat saat pelanggan menekan tombol.
Branding, domain panel, name server
Panel Anda membawa merek dan domain Anda: pelanggan melihat logo, warna, nama, dan alamat dukungan Anda, bukan NBT Host. Semuanya bisa diatur di panel (Pengaturan → Branding, Pengaturan → Platform) atau melalui API.
/orgs/{ORG}/websites?kind=controlPanelDomain panel Anda: {"domain":"panel.agensi-anda.co.id"}. Sebelumnya, di DNS Anda: panel.agensi-anda.co.id A 185.230.138.193. Jika sudah ada: 409 already_exists — tambahkan nama baru sebagai alias di situs panel (POST …/websites/{id}/domains dengan "kind":"alias") lalu jadikan utama (PUT …/domains/primary)./orgs/{ORG}/websites?kind=controlPanelSitus panel, dengan domain.id (untuk sertifikat)./orgs/{ORG}/name-serversName server Anda: {"domain":"ns1.agensi-anda.co.id"}, lalu sama untuk ns2./orgs/{ORG}/branding/settingsPengaturan branding./orgs/{ORG}/branding/settings/{name}Satu pengaturan (misalnya sge_from_email = alamat pengirim email panel, sebagai string JSON)./orgs/{ORG}/branding/logoLogo (multipart, field logo; maks. 200 KiB, png / svg / jpg). Sama halnya: inverse-logo, favicon, login-image (maks. 2 MiB), inverse-icon./orgs/{ORG}/branding/logoHapus logo (sama untuk gambar lainnya).curl -sS -X POST "$NBT_API/orgs/$NBT_ORG/websites?kind=controlPanel" \
-H "Authorization: Bearer $NBT_TOKEN" -H 'Content-Type: application/json' -d '{"domain":"panel.agensi-anda.co.id"}'
curl -sS -X PUT "$NBT_API/orgs/$NBT_ORG/branding/logo" -H "Authorization: Bearer $NBT_TOKEN" -F 'logo=@logo.svg'- Sertifikat domain panel terpasang otomatis dalam beberapa menit jika DNS sudah mengarah ke server; jika belum,
letsencrypt_preflight+letsencryptpadadomain.id-nya (SSL). - Name server Anda: di zona domain Anda tambahkan
ns1.agensi-anda.co.id A 185.230.138.193danns2.agensi-anda.co.id A 213.199.48.100. Sejak itu zona pelanggan Anda memakai record NS Anda, dan pelanggan mengaturnya di registrar mereka. - Gunakan alamat pengirim (
sge_from_email) di domain yang di-hosting di tempat kami, agar email panel (reset kata sandi, undangan) lolos SPF / DKIM.
Error
Error memiliki status HTTP dan biasanya body JSON: {"code":"…","detail":"…","message":"…"} (detail dan message bisa tidak ada). Tulis kode Anda berdasarkan code, bukan teks message.
| HTTP | code | Kapan muncul (respons nyata) |
|---|---|---|
| 400 | invalid_argument | Field yang salah: kata sandi terlalu sederhana, versi PHP tidak diizinkan, paket tanpa allowedPhpVersions, token dengan peran Owner, format token salah (“invalid length: expected length 32…”). |
| 400 | — (teks) | Parameter query salah, body berupa teks: Query deserialize error: invalid digit found in string (misalnya limit=abc). |
| 401 | no_session_token | Header Authorization tidak ada. |
| 403 | unauthorized | Token salah, kedaluwarsa, dicabut, atau dipakai dari IP lain; atau sumber daya di luar organisasi Anda (“Only a reseller or the MO may perform this operation”, “Unable to create website outside of the org”). |
| 403 | only_mo_allowed | Operasi khusus administrator platform: force=true, server, grup server, batas memori / CPU. |
| 403 | resource_out_of_quota | Melebihi kuota: situs kedua pada paket satu situs, kotak surat ke-6 dari 5, paket pelanggan yang lebih besar dari paket Anda (“The total is 10, the usage is 0, while the requested quota is: 11”). |
| 403 | non_existent_allowance | Fitur yang tidak ada di paket Anda (misalnya featureSSH). |
| 403 | suspended | Paket Anda ditangguhkan: “Cannot perform actions on suspended entity 'subscription'”. Baca tetap bisa, tulis pada pelanggan tidak. |
| 403 | not_allowed | Fitur yang tidak termasuk dalam paket (misalnya “Branding not enabled on your subscription”). |
| 404 | not_found | detail menyebutkan apa yang tidak ada: {"code":"not_found","detail":"website"}, "subscription", "backup", "org". |
| 404 | — (teks) | Id di path yang bukan uuid valid: UUID parsing failed: invalid character…. |
| 429 | — | Terlalu banyak permintaan (lihat Batas). Tunggu Retry-After detik, atau 2, 4, 8 detik, lalu ulangi. |
| 500 | — (teks) | “An unknown error occurred, please try again later”: error server atau aplikasi di situs (misalnya daftar plugin WordPress yang rusak). Coba sekali lagi; jika tetap terjadi, hubungi kami dengan waktu dan path-nya. |
Batas
- Kuota paket Anda (pelanggan, situs, penyimpanan, kotak surat, database, subdomain, alias, FTP) adalah total untuk semua pelanggan:
GET /orgs/{ORG}/subscriptions→resources[]denganusagedantotal(tanpatotal= tidak terbatas). Paket pelanggan tidak bisa melampauinya, dan situs ke-N+1 menerima403 resource_out_of_quotameskipun paket pelanggan masih punya ruang. - Pemakaian dihitung saat dipakai: pelanggan memakai satu slot sejak organisasinya dibuat (bukan sejak berlangganan), situs sejak dibuat. Organisasi kosong yang terlupakan tetap memakai slot: hapuslah.
- Memori dan CPU: setiap situs mendapat batas dari paket Anda (
GET …/cgroup_limits); tidak bisa diubah lewat API. - Permintaan: kami belum menemui batas (90 permintaan dalam 17 detik, semuanya 200), tetapi itu bukan jaminan: tetaplah di bawah 5 permintaan per detik, gunakan paginasi, dan tangani
429dengan percobaan ulang (fungsi bantu di Autentikasi sudah melakukannya). - Email keluar memiliki batas per jam di tingkat server, untuk mencegah spam.
Yang TIDAK bisa Anda lakukan
- Root atau SSH — baik Anda maupun pelanggan Anda. Kunci SSH dan crontab yang ditambahkan di luar paket dihapus otomatis oleh pemeriksaan per jam kami.
- Server eksternal — Anda tidak bisa menambahkan server, memilih grup server, atau mengubah batas memori dan CPU (
403 only_mo_allowed). VPS Mitra 50 / 100 adalah bagian dari klaster NBT Host. - Sub-reseller — paket pelanggan Anda tidak bisa memiliki pelanggan: “Cannot create a plan with customers where sub-reselling it not enabled” (
400). - Overselling — total yang dijual ke pelanggan tidak bisa melebihi kuota Anda.
- Penghapusan permanen (
force=true) — kami yang melakukannya, atas permintaan. - Domain addon dan PostgreSQL — tidak termasuk.
- Domain milik organisasi lain dan subdomainnya (misalnya
*.nbt-host.ro) — ditolak dengan403. - Pelanggan, server, dan backup NBT Host atau mitra lain — token Anda hanya melihat organisasi Anda dan pelanggan Anda (
403 unauthorized).
Pertanyaan umum
Apakah saya perlu membeli lisensi Enhance atau memiliki kontrak dengan Enhance?
Tidak. Lisensi Enhance sudah termasuk dalam harga paket mitra dan disediakan oleh NBT Host. Anda tidak memiliki kontrak langsung dengan Enhance: Anda bekerja di panel Enhance milik NBT Host, dengan merek dan domain Anda sendiri.
Apakah saya mendapat akses root di VPS Mitra 50 / 100? Bisakah saya menambahkan server sendiri?
Tidak. VPS yang termasuk dalam paket bergabung ke klaster NBT Host: situs pelanggan Anda berjalan di sana, sementara pembaruan, keamanan, dan backup tetap ditangani kami. Server dari penyedia lain tidak dapat ditambahkan.
URL API mana yang dipakai jika panel saya ada di domain saya sendiri?
https://server.nbt-host.com/api. Domain panel Anda untuk manusia (Anda dan pelanggan Anda, di browser); integrasi memakai alamat di atas.
Token saya hilang. Bisakah saya melihatnya lagi?
Tidak: panel hanya menampilkannya sekali. Buat token baru dan hapus yang lama (Rotasi).
Apakah pelanggan saya melihat NBT Host di suatu tempat?
Tidak di panel, setelah Anda mengatur domain, logo, favicon, dan alamat pengirim. Zona DNS bisa memakai name server Anda sebagai ganti milik kami.
Apa yang terjadi pada pelanggan saya jika langganan saya belum dibayar?
Saat paket Anda ditangguhkan, pelanggan Anda juga ditangguhkan (situs mereka menjawab 404). Token Anda masih bisa membaca, tetapi penulisan menerima 403 suspended. Saat diaktifkan kembali, semua yang ditangguhkan bersama paket Anda kembali aktif.
Apakah ada lingkungan uji (sandbox)?
Tidak ada yang terpisah. Buat paket uji dengan batas kecil dan pelanggan uji, lalu hapus. Pelanggan uji memakai satu slot kuota selama masih ada.
Dukungan dan kontak
Untuk API, panel, dan server, hubungi kami. Untuk pelanggan Anda (situs, email, dan keluhan mereka) Anda adalah kontak pertama: Anda yang mendukung mereka, kami yang mendukung Anda.
Agar kami bisa membantu dengan cepat, kirimkan: metode dan path (tanpa token), waktu permintaan, status HTTP, dan body respons. Jangan pernah mengirimkan token Anda kepada kami; jika token sudah terkirim dalam pesan, cabut token tersebut.
