Developers: the API, the CLI and OpenAPI

Everything for automating VPSNine in one place. The JSON API and its reference, the OpenAPI document, the vps9 CLI, request ids, rate limits and safe retries.

VPSNine has a JSON API at https://my.vpsnine.com/api/v1 for everything you do in the panel: ordering, powering and reinstalling servers, and managing keys, firewalls, snapshots, reverse DNS, add-ons, invoices and webhooks. The vps9 CLI, the TypeScript SDK and the OpenAPI document are all built on that one API, and this page shows which to reach for.

The API reference: links to the OpenAPI document, the changelog, the Markdown version and the vps9 CLI, the contents on the left, and the Try it in this page box for a token
The API reference at my.vpsnine.com/api. Paste a token in Try it in this page to send real requests from the examples.

Pick a tool

You want to Use
Run a command now, or write a shell script The vps9 CLI
Call the API from any language The API reference, with examples in curl, JavaScript and Python
Generate a client, or import the API into Postman, Insomnia or Bruno The OpenAPI document: openapi.json or openapi.yaml
Feed the reference to an LLM or a docs tool api.md, the same reference as Markdown
See what changed The API changelog
Let Claude, Cursor or VS Code manage servers for you The MCP server, remote at https://my.vpsnine.com/mcp or local
Script in TypeScript or JavaScript The TypeScript SDK (typed methods, retries, idempotency keys)
React to events instead of polling Webhooks

All of them need an API token. A read-only token is enough for anything that only looks; changing something takes a read-and-write token. For CI jobs and scripts, API tokens for CI and automation covers scopes, address limits and rotation.

The reference, and Try it

The API reference lists every endpoint with its parameters, its errors, an example answer and the same call in curl, JavaScript (fetch), Python (requests) and the vps9 CLI where it has the command. Your choice of language sticks as you move between endpoints.

Each endpoint has a Try it button. Paste a token and the page sends the request from your browser to my.vpsnine.com/api/v1 and shows the answer, its status and its request id. The token stays in the page: it isn't saved anywhere and goes to no other address, and reloading the page forgets it. Anything other than a GET asks you to tick a box first, because it really happens: a reboot reboots, a delete deletes, and an order makes an invoice. A read-only token is the safe way to explore.

OpenAPI

openapi.json is an OpenAPI 3.1 description of the whole API, made from the same source as the reference, so the two always agree. It has the schemas of every request and answer, the bearer-token security scheme, the error answers, the rate-limit headers and the Idempotency-Key and If-Match headers where they apply. Each operation also names its scope (x-scope), its error codes (x-error-codes) and its vps9 command (x-cli).

Load it by URL in most API tools, or generate a client with openapi-generator 7.20.0 or later; Use the OpenAPI spec has the steps for Python, Postman, Insomnia and Bruno:

bash
curl -sO https://my.vpsnine.com/api/openapi.json
docker run --rm -v "$PWD:/local" openapitools/openapi-generator-cli:v7.20.0 generate \
  -i /local/openapi.json -g python -o /local/vps9-client --package-name vps9_client

Request ids

Every answer carries an X-Request-Id header, like req_7d2kq4m5x3n6p2r4s7t2v3w4, and every error repeats it:

json
{"error":{"code":"not_found","message":"No such server.","requestId":"req_7d2kq4m5x3n6p2r4s7t2v3w4"}}

If something looks wrong, put the request id in your support ticket. We log each request under its id with the route, the status and how long it took (never your token or what you sent), so we can find exactly that call. The vps9 CLI prints the request id under any error the API gives.

Rate limits

Each token can make 60 requests a minute, and each account 120 across all its tokens. Answers tell you where you stand:

Header Meaning
X-RateLimit-Limit 60, or 120 once the account's limit is the nearer one
X-RateLimit-Remaining Requests left this minute
X-RateLimit-Reset Seconds until the minute starts again

Past the limit you get 429 rate_limited with a Retry-After header in seconds. Slow down when X-RateLimit-Remaining gets low rather than waiting for the 429. Rate limits and request ids has retry helpers for shell and Python, and the other limits (orders, reverse DNS, rescue).

Retrying safely

Some failures are worth trying again unchanged: 429, 500 and 503 (a 503 from the API means nothing changed). A 4xx means the request itself needs changing.

Be careful with a POST that timed out: it may have worked. Reading, replacing (PUT) and deleting can always be sent again, because doing them twice ends the same way. Ordering a server is the exception that matters, so POST /servers takes an Idempotency-Key header. Send the same key on every retry of one order and you get that order back instead of a second one:

bash
ORDER_KEY="$(uuidgen)"   # keep it until you have an answer
curl -s -X POST -H "Authorization: Bearer $VPS9_TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $ORDER_KEY" \
  -d '{"plan":"standard","image":"ubuntu-24.04","hostname":"web-1","sshKeyIds":["key_…"]}' \
  https://my.vpsnine.com/api/v1/servers

vps9 servers create --idempotency-key does the same from the CLI. Idempotent orders covers the key's rules and the idempotency_key_reused error.

Waiting for work to finish

Work that happens on the server (building, rebooting, reinstalling, snapshots, firewall changes) answers 202 straight away and finishes in the background. Read the object again to follow it: a server's pendingAction goes back to null, a snapshot's state becomes ready, a firewall's status becomes applied. Every few seconds is plenty; most actions take under a minute.

Webhooks instead of polling

Rather than reading a server every few seconds, register an HTTPS endpoint and we send it signed JSON events as they happen: server.ready, snapshot.completed, alert.triggered, invoice.paid and more. Webhooks and verifying their signatures covers the panel side; Receive VPSNine webhooks in Node.js and Python builds a small receiver that checks every signature, and Slack and Discord alerts from VPSNine webhooks relays events to chat.

Editing the firewall without overwriting someone else

GET /servers/{id}/firewall sends an ETag like "r3". Send it back as If-Match on your PUT and the save only happens if nobody saved since; otherwise you get 412 firewall_changed and nothing changes. The CLI does this for you on every firewall edit.

The site from a terminal

curl vpsnine.com answers with text made for a terminal: the plans with their current prices, a line of live status and the commands to try next. The same works for /plans, /status, /faq, /help and every guide and blog post, so curl vpsnine.com/help/ssh-keys reads a guide without leaving the shell. curl, Wget, HTTPie and xh get colors; add ?nocolor for plain text, and ?width=100 to wrap at another width. Any client that sends Accept: text/plain gets the plain version too. Browsers get the normal page at the same address.

For scripts there are two JSON files that need no token: plans.json, with every plan's specs, its live price in US cents and the add-ons, and locations.json. With jq:

bash
curl -s https://vpsnine.com/plans.json | jq -r '.plans[] | "\(.name)\t\(.price.monthly // "at launch")"'

AI tools (MCP)

The VPSNine MCP server gives AI assistants the API as tools: Claude Code, Cursor and VS Code connect to https://my.vpsnine.com/mcp with a token in the Authorization header, and Claude Desktop runs a small local program. Each tool call is an API request with the token's scopes, role and limits. Ordering and add-on changes answer with the price first, and reinstalling, deleting and reverting need the server's hostname typed back.

Where next

Tutorials

Step-by-step guides for common automation, each tested against a local copy of the API:

Doing it on VPSNine

Everything here works with any plan: the API, the CLI and webhooks come with every account.

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.

  • One email, on launch day
  • Monthly or yearly, no lock-in
  • 14-day money-back guarantee