Use the VPSNine OpenAPI spec

Download the OpenAPI 3.1 description of the VPSNine API, generate a typed client with openapi-generator, and import the API into Postman, Insomnia or Bruno.

The VPSNine API is described by an OpenAPI 3.1 document at my.vpsnine.com/api/openapi.json (and openapi.yaml). Point a code generator or an API client at that URL to get every endpoint, its parameters, its answers and its errors, with bearer-token authentication already set up.

What you need

  • An API token. Read-only is enough to explore.
  • For generating a client: Docker, or Java 11 or later with Node.js for the npm wrapper.

What's in the document

It's built from the same table as the API reference, and a test holds both to the real routes, so the spec can't list an endpoint that doesn't exist or miss one that does.

  • servers: https://my.vpsnine.com/api/v1.
  • A bearerAuth security scheme on every operation except GET /prices and GET /status.
  • Named schemas for requests and answers (Server, NewServer, Firewall, Snapshot, Invoice and the rest), and the Error shape every failure uses.
  • The X-Request-Id and X-RateLimit-* headers on every answer, and the Idempotency-Key and If-Match request headers where they apply.
  • Three extensions on each operation: x-scope (read or write), x-error-codes (the codes it can answer) and x-cli (the vps9 command that does the same, when there is one).

info.version is the date of the newest API changelog entry.

Download it:

bash
curl -sO https://my.vpsnine.com/api/openapi.json
jq -r '.info.version, (.paths | length)' openapi.json

The file is served with Access-Control-Allow-Origin: *, so browser-based tools can load it by URL too.

Generate a client with openapi-generator

openapi-generator writes clients for many languages from the spec. Use version 7.20.0 or later: older 7.x releases misread nullable fields ("type": ["string", "null"]) inside inline schemas, and the generated Python client then refuses a server whose ipv6 or label is null.

With Docker:

bash
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

Or with the npm wrapper, which downloads the Java generator for you:

bash
npx @openapitools/openapi-generator-cli version-manager set 7.20.0
npx @openapitools/openapi-generator-cli generate \
  -i openapi.json -g python -o vps9-client --package-name vps9_client

Install it and call the API. Every tag in the spec becomes a class (ServersApi, SnapshotsApi, FirewallApi …) and every operationId a method:

bash
python3 -m venv .venv && . .venv/bin/activate
pip install ./vps9-client
python
import os
import vps9_client

config = vps9_client.Configuration(
    host=os.environ.get("VPS9_API_URL", "https://my.vpsnine.com/api/v1"),
    access_token=os.environ["VPS9_TOKEN"],
)
with vps9_client.ApiClient(config) as client:
    servers = vps9_client.ServersApi(client).list_servers()
    for s in servers.data:
        print(s.hostname, s.state, s.ipv4)
    try:
        vps9_client.ServersApi(client).get_server("srv_doesnotexist")
    except vps9_client.ApiException as e:
        print(e.status, e.body)

We generated this client with 7.20.0 and ran the script against a local copy of the API: it listed the servers, and the second call printed 404 with the JSON error and its request id. Other generators (-g go, -g typescript-fetch, -g ruby and so on) read the same document; check the result against a read-only token before you trust it with writes.

For TypeScript and JavaScript there's a VPSNine SDK made from this spec, with retries and idempotency keys built in, so you may not need to generate one.

Import into Postman, Insomnia or Bruno

All three import OpenAPI 3 documents and make one request per endpoint, grouped by tag:

  • Postman: Import, then paste https://my.vpsnine.com/api/openapi.json.
  • Insomnia: Import, then From URL, with the same address.
  • Bruno: Import Collection, then OpenAPI V3 Spec, and pick the downloaded openapi.json.

Then give the collection your token once. The spec's bearer scheme becomes the collection's auth: set it to Bearer Token with a variable such as {{vps9_token}}, and keep the token in an environment or secret variable rather than in the collection itself, so exporting or sharing the collection never shares the token.

Requests that change something (POST, PUT, DELETE) are real. Use a read-only token while you explore, and a read-and-write one only when you mean it.

Check it worked

Send Who am I (GET /me) from the generated client or the imported collection. A 200 with your email means the base URL and the token are right. A 401 means the token isn't being sent: look at the auth settings of the collection or the access_token of the client.

Troubleshooting

ValidationError … Input should be a valid string … input_value=None in a generated Python client. The generator is older than 7.20.0. Regenerate with 7.20.0 or later.

Every request answers 415 unsupported_media_type. The tool is sending the body as a form. Set the body type to JSON, which adds Content-Type: application/json.

404 on every request. The base URL is missing /api/v1. It should be https://my.vpsnine.com/api/v1.

Next steps

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