# NoctHost - API guide for AI agents > NoctHost resells cloud servers from Vultr, DigitalOcean, Hetzner and Linode > through one account, one balance and one REST API (JSON), billed by the hour. > Each server is a real instance at that provider (NVMe, dedicated IPv4, root > SSH), created through the provider's API, not a container or a slice of our > own Proxmox host. Signing up needs only an email. > > What can be deployed: shared-vCPU VPS, dedicated-CPU machines (cores not > shared with anyone), NVIDIA GPU servers by the hour, and whole physical > machines (bare metal, no hypervisor, no snapshots). > > Paying: crypto first. USDT (Tron, BSC, Ethereum, Polygon) from $5 and 300+ > other coins from $20, no ID documents (no KYC) for crypto. Cards (Visa, Mastercard, plus Apple Pay or > Google Pay where the browser supports it) from $20, processed by our payment > partner, which collects billing details. Top-ups are made in the dashboard. > > Base URL: https://api.nocthost.com > Human docs: /docs · This file: /llms.txt · Everything in one file: /llms-full.txt ## Happy path (deploy one server) 1. POST /auth/register {"email":"...","password":"min 8 chars"} -> 201 {"accessToken":"","user":{...}} (or POST /auth/login if registered) 2. Send "Authorization: Bearer " on every request below. For scripts, create a non-expiring API key in the dashboard (Profile -> API keys) and send it the same way: "Authorization: Bearer nh_...". 3. GET /billing -> {"balance":"10.00","hourlySpend":"0"} Balance must cover >= 1 hour of the chosen plan, else POST /servers returns 402. 4. POST /servers {"label":"my-bot","planId":"vc2-1c-1gb","regionId":"ams","password":""} -> 202 {"server":{"id":"...","status":"PROVISIONING","ipv4":null,...}} The password sets the server's root login; it is never stored, so keep it. 5. Poll GET /servers/ every ~5s until "status":"ACTIVE" (typically ~60s). Then "ipv4" is set - SSH in as root with the password you chose. 6. DELETE /servers/ -> 202. Billing for it stops the same hour. ## Endpoints POST /auth/register Create an account. Email + password is all that is needed. body: {"email":"agent@example.com","password":"min-8-chars"} returns: 201 {"accessToken":"","user":{"id","email","balance"}} POST /auth/login Get a fresh access token (expires in 15 minutes). body: {"email":"...","password":"..."} returns: 200 {"accessToken":"","user":{...}} GET /auth/me (auth) Whoami: id, email and current balance. returns: 200 {"user":{"id","email","balance":"9.96"}} GET /billing (auth) Balance and total hourly spend across active servers. returns: 200 {"balance":"9.96","hourlySpend":"0.012"} GET /servers (auth) List all non-destroyed servers. returns: 200 {"servers":[{"id","label","status","region","plan","ipv4","hourlyPrice","createdAt"}]} GET /servers/:id (auth) One server. Poll this every ~5s after a deploy. returns: 200 {"server":{...,"status":"ACTIVE","ipv4":"203.0.113.10"}} GET /servers/providers (auth) Which backends can take a deploy right now, and which of their regions are temporarily out of capacity. Check this before picking providerId/regionId. returns: 200 {"providers":[{"id":"vultr","label","available":true}],"outages":{"hetzner":{"fra":"..."}}} POST /servers (auth) Deploy one server. Async: 202 = accepted, not yet running. Optional osId (see the OS list in the catalog below, default Ubuntu 22.04) or appSlug (one-click app, Vultr only) - pick at most one. osId works on every provider; each supports a subset of the list, and an OS the chosen provider does not carry returns 400. Optional sshKey installs a public key for root at first boot. body: {"label":"my-bot","planId":"vc2-1c-1gb","regionId":"ams","osId":1743,"providerId":"vultr","password":"12-72 chars, no spaces","sshKey":"ssh-ed25519 AAAA... you@host"} returns: 202 {"server":{...,"status":"PROVISIONING"}} POST /servers/bulk (auth) Deploy up to 10 servers in one call. Labels get -1..-N suffixes. body: {"label":"fleet","count":10,"planId":"vc2-1c-1gb","regionId":"ams","password":"applied to all","sshKey":"optional, applied to all"} returns: 202 {"servers":[...10 items, all "PROVISIONING"]} POST /servers/:id/reboot (auth) Reboot a running server. returns: 200 {"server":{...}} POST /servers/:id/stop (auth) Power off a server. STOPPED is still billed while it exists. returns: 200 {"server":{...,"status":"STOPPED"}} POST /servers/:id/start (auth) Power a STOPPED server back on. returns: 200 {"server":{...,"status":"ACTIVE"}} POST /servers/:id/root-password (auth) Set a new root password without erasing the disk, where the server page shows "Change root password". The server must be running; Linode servers without our recovery key must be stopped first. On Hetzner without the recovery key the password you send is ignored: Hetzner generates one and returns it (matchesRequested: false). The password is shown only in this response. body: {"password":"12-72 chars, no spaces"} returns: 200 {"password":"...","matchesRequested":true,"note":"..."} DELETE /servers/:id (auth) Destroy a server. Billing stops the same hour. returns: 202 {"ok":true} GET /backups (auth) List your backups (full disk snapshots, kept 7 days). returns: 200 {"backups":[{"id","label","status","region","plan","createdAt","expiresAt"}]} POST /backups (auth) Back up a server. Async: snapshot takes minutes, PENDING -> AVAILABLE. body: {"serverId":""} returns: 202 {"backup":{...,"status":"PENDING"}} POST /backups/:id/restore (auth) Restore an AVAILABLE backup onto a new server (gets a new IP). password is required: the root password of the restored server (12–72 Latin chars, 3 of lower/upper/digits/symbols, no spaces). Optional planId restores onto a bigger plan. body: {"password":"","planId":""} returns: 202 {"server":{...,"status":"PROVISIONING"}} DELETE /backups/:id (auth) Delete a backup before its 7-day expiry. returns: 202 {"ok":true} ## Catalog Two kinds of planId work, and this is the part agents get wrong most often. 1. Our own eight tiers, priced the same on every provider (list below). 2. Any provider-native size id from the wider catalog, passed as planId exactly as the provider names it: c-2, g2-gpu-rtx4000a1-s. That is where dedicated-CPU machines and GPU cards live. In total 225 native sizes, $10 to $7000/mo: 127 with dedicated cores, 17 with an NVIDIA card (GPU is priced by the hour, from $0.085/hr). GET /servers/providers returns what is deployable right now; a size that the provider does not currently allocate to us is refused at deploy time. plans: vc2-1c-1gb Micro (1 vCPU / 1 GB RAM / 25 GB SSD / 500 GB traffic, $10/mo) · vc2-1c-2gb Starter (1 vCPU / 2 GB RAM / 50 GB SSD / 2048 GB traffic, $18/mo) · vc2-2c-4gb Standard (2 vCPU / 4 GB RAM / 80 GB SSD / 3072 GB traffic, $34/mo) · vc2-4c-8gb Pro (4 vCPU / 8 GB RAM / 160 GB SSD / 4096 GB traffic, $62/mo) · vc2-6c-16gb Beast (6 vCPU / 16 GB RAM / 320 GB SSD / 5120 GB traffic, $120/mo) · vc2-8c-32gb Titan (8 vCPU / 32 GB RAM / 640 GB SSD / 6144 GB traffic, $240/mo) · vc2-16c-64gb Colossus (16 vCPU / 64 GB RAM / 1280 GB SSD / 10240 GB traffic, $480/mo) · vc2-24c-96gb Leviathan (24 vCPU / 96 GB RAM / 1600 GB SSD / 15360 GB traffic, $960/mo) regions: ams fra cdg lhr man mad waw sto hel nbg · ewr ord dfw atl mia sea lax sjc yto mex · sao scl · nrt itm icn sgp blr bom del · syd mel · jnb tlv os: 2760 Ubuntu 26.04 LTS (vultr) · 2284 Ubuntu 24.04 LTS (all providers) · 1743 Ubuntu 22.04 LTS (all providers) · 2625 Debian 13 (Trixie) (vultr) · 2136 Debian 12 (Bookworm) (vultr, hetzner, linode) · 477 Debian 11 (Bullseye) (vultr, hetzner, linode) · 2593 AlmaLinux 10 (vultr) · 1868 AlmaLinux 9 (all providers) · 2594 Rocky Linux 10 (vultr) · 1869 Rocky Linux 9 (all providers) · 2467 CentOS Stream 10 (vultr) · 542 CentOS Stream 9 (all providers) · 2752 Fedora 44 (vultr, digitalocean) · 2658 Fedora 43 (vultr, linode) · 501 Windows Server 2022 (vultr, Windows: extra licence fee, RDP instead of SSH, needs a plan with >= 4 GB RAM) · 371 Windows Server 2019 (vultr, Windows: extra licence fee, RDP instead of SSH, needs a plan with >= 4 GB RAM) · 2514 Windows Server 2025 (vultr, Windows: extra licence fee, RDP instead of SSH, needs a plan with >= 4 GB RAM) osId is optional; omit it and you get 1743 Ubuntu 22.04 LTS. Each provider carries a subset of the list (shown in brackets) - asking for an OS the chosen provider does not have returns 400, so either pick one marked "all providers" or match it to your providerId. Regions and plans work the same way: not every provider serves every city. GET /servers/providers says which backends can take a deploy right now and which of their regions are temporarily out of capacity. Hourly price is returned on the server object at deploy time and never changes for a running server. ## Server statuses PROVISIONING -> ACTIVE (success) | ERROR (failed, not billed further) ACTIVE <-> STOPPED (powered off via /servers/:id/stop or /start; STOPPED is still billed while it exists) DESTROYING -> DESTROYED SUSPENDED = balance ran out or abuse hold; server is off but recoverable. ARCHIVED = balance ran out; the instance is deleted but your data is kept in a snapshot. Top up to restore. ## Backups On-demand backups are Vultr-only for now (DigitalOcean/Linode cannot be backed up on demand). Full disk snapshots, kept 7 days, then auto-deleted. POST /backups {"serverId"} -> snapshot (PENDING -> AVAILABLE, takes minutes). POST /backups//restore {"password", "planId"?} -> new server from the snapshot (new IP, same region; same plan unless planId). password (root password of the new server) is required. Backup statuses: PENDING -> AVAILABLE | ERROR; EXPIRED once deleted. ## Errors 400 validation failed ("details" in body) | 401 token expired -> re-login, retry once 402 insufficient balance -> top up | 403 suspended or server limit (default 10, lower during promos) 404 not yours / not found | 409 already being destroyed 429 rate limited (300 req/min authenticated, 10/min on /auth/*) -> exponential backoff ## Rules for agents - Deploys are asynchronous. 202 means accepted; poll GET /servers/:id every ~5 seconds until status is ACTIVE (typically ~60s) or ERROR. - For automation, prefer a personal API key over login: create one in the dashboard under Profile, then send it as "Authorization: Bearer nh_...". It does not expire, is revocable, and needs no re-login. Login-issued access tokens (JWT) still work but expire after 15 minutes. - Access tokens (from POST /auth/login) expire after 15 minutes. On a 401 with a JWT, call POST /auth/login again and retry once. API keys (nh_...) do not expire - a 401 there means the key was revoked. - Money values (balance, hourlyPrice, hourlySpend) are strings - parse as decimal, never float-math them. - Check GET /billing before deploying: the balance must cover at least one hour per server, or you get 402. - Server labels must match ^[a-zA-Z0-9._-]+$ (max 64 chars). - sshKey takes one public key line (ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256/384/521 or the sk- hardware variants) and installs it for root at first boot, on POST /servers and POST /servers/bulk alike. It does not replace password: that stays required, because the provider's web console and account recovery both run on it, and a key with a typo in it would otherwise lock you out of a server you just paid for. Turn password login off inside the server once your key works. Windows servers ignore it, they use RDP. - providerId is optional and defaults to "vultr". "digitalocean", "hetzner" and "linode" are also available, each Linux-only and each serving a subset of the regions, plans and OS ids. Sending an unsupported combination returns 400; GET /servers/providers lists what each one takes right now. - The default account limit is 10 active servers (temporarily lower, e.g. 5, during a promo) and can be raised. 403 with a limit message means destroy something first or ask for a raise via /docs/custom-requests. - Rate limit is 300 requests/minute with an API key or token (100/min without auth, 10/min on auth routes). On 429, back off exponentially. - Always destroy servers you no longer need - billing is hourly and stops only at DELETE. - On-demand backups (POST /backups) are Vultr-only for now, DigitalOcean/Linode servers cannot be backed up on demand (automatic snapshots on suspension still work on any provider). Backups are full disk snapshots kept 7 days. POST /backups is async (PENDING -> AVAILABLE, minutes); only restore once AVAILABLE. Restore creates a new server with a new IP.