api v1

Void API — your domains, servers and hosting, over REST.

Register and renew domains, put them behind Cloudflare and manage DNS, order and run VPS servers and web hosting — from your own code, on the same account and balance as the bot.

https://api.void.cd/v1 Bearer void_… JSON · UTC · USD strings

Hosting

shared web hosting with a control panel

A hosting account is a user on our HestiaCP panel with the plan's limits (sites, disk, databases, mailboxes). It is created while you wait: POST /hosting answers 201 with an ACTIVE account, or fails and refunds the charge. The domain does not have to be registered with us: point its A record at ip, or its nameservers at nameservers. A domain bought on Void comes off the parking page automatically. The panel password is returned only by GET /hosting/{id}/credentials.

# 1. plans and prices
curl -s "$API/hosting/catalogue" -H "Authorization: Bearer $VOID_KEY"

# 2. order (charges the term, returns 201 + the account, already ACTIVE)
curl -s -X POST "$API/hosting" -H "Authorization: Bearer $VOID_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan":"web-start","domain":"example.org","period":"MONTH"}'

# 3. panel URL, login and password
curl -s "$API/hosting/$ID/credentials" -H "Authorization: Bearer $VOID_KEY"
// call() as in the Quickstart
const { plans } = await call("GET", "/hosting/catalogue");
const hosting = await call("POST", "/hosting", { plan: plans[0].code, domain: "example.org", period: "MONTH" });

// point example.org at hosting.ip (A record) or at hosting.nameservers
const { panelUrl, login, password } = await call("GET", `/hosting/${hosting.id}/credentials`);
# call() as in the Quickstart
plans = call("GET", "/hosting/catalogue")["plans"]
hosting = call("POST", "/hosting", plan=plans[0]["code"], domain="example.org", period="MONTH")

# point example.org at hosting["ip"] (A record) or at hosting["nameservers"]
creds = call("GET", f"/hosting/{hosting['id']}/credentials")   # panelUrl, login, password
GET/hosting/catalogue

Plans on sale with the price of every term. available: false means hosting sales are switched off right now — an order would fail with PROVIDER_DISABLED. Plans come in display order; id is what Hosting.planId refers to.

{ "ok": true, "data": { "available": true, "plans": [
    { "id": "8d2f…", "code": "web-start", "nameEn": "Start", "nameRu": "Старт", "sites": 1, "diskMb": 3072, "bandwidthGb": 0, "databases": 1, "mailboxes": 3,
      "prices": { "MONTH": "10.00", "QUARTER": "29.25", "HALF_YEAR": "57.00", "YEAR": "111.00" } }, … ] } }
GET/hosting?offset=0&limit=20

Your live accounts (PENDING, ACTIVE, SUSPENDED), newest first. At most 50 per page.

{ "ok": true, "data": { "items": [ Hosting, … ], "total": 1, "offset": 0, "limit": 20 } }
POST/hosting201 · charges balance

Charges the term and creates the panel account with the domain as its first site. Counts against the 20 / minute limit.

bodytype
planrequiredstringplan code from the catalogue
domainrequiredstringthe site's domain; one domain can live on one hosting account only
periodrequiredMONTH QUARTER HALF_YEAR YEARthe paid term
{ "plan": "web-start", "domain": "example.org", "period": "YEAR" }
402 INSUFFICIENT_FUNDS409 DOMAIN_UNAVAILABLE already on a hosting account400 DOMAIN_INVALID404 PLAN_NOT_FOUND · 400 PLAN_INACTIVE5xx PROVIDER_ERROR refunded

A repeated order for the same domain fails with 409 DOMAIN_UNAVAILABLE once the first one succeeded, so a retry cannot buy the account twice.

GET/hosting/{id}

One account — see Hosting.

GET/hosting/{id}/credentials

Panel address, login and password — the only place the password is returned.

{ "ok": true, "data": { "panelUrl": "https://…", "login": "wh3f9a1c", "password": "…" } }
PATCH/hosting/{id}

{ "autoRenew": true | false } — at expiry, renew for the current term from the balance; if the balance is short the account is suspended instead. ACTIVE / SUSPENDED accounts only. Returns the account.

POST/hosting/{id}/renewcharges balance

Charges periodPrice now and extends expiresAt by one term from the later of the current expiry and now. A SUSPENDED account becomes ACTIVE and the panel user is unsuspended within minutes. Each successful call adds another term.

402 INSUFFICIENT_FUNDS400 HOSTING_NOT_ACTIVE
GET/hosting/{id}/term

Every renewal term with its price at today's rates; current marks the account's term. Same shape as for servers.

{ "ok": true, "data": [ { "period": "MONTH", "price": "10.00", "current": true }, { "period": "QUARTER", "price": "29.25", "current": false }, … ] }
PUT/hosting/{id}/term

{ "period": "YEAR" } — switches the renewal term. Nothing is charged now and expiresAt stays; the new term and its price apply from the next renewal, automatic or manual.

POST/hosting/{id}/plan/quote

{ "plan": "web-plus" } — the price of moving to a bigger plan. Only a more expensive plan is accepted (a smaller one may not fit what is already on the account — ask support). charge is due now: the difference in term price, pro rata for the rest of the paid term; periodPrice is each renewal afterwards.

{ "ok": true, "data": { "hostingId": "c41e…", "planCode": "web-plus", "charge": "4.52", "periodPrice": "22.00", "period": "MONTH" } }
POST/hosting/{id}/plancharges balance

{ "plan": "web-plus", "maxCharge": "4.52" } — charges the difference immediately and switches the panel package right away; returns the applied quote. If the price is now above maxCharge, nothing is charged and the call answers 400 UPGRADE_PRICE_CHANGED with details: { "charge" }. If the panel refuses the change, the charge is refunded and the old plan restored.

400 UPGRADE_PRICE_CHANGED400 VALIDATION_ERROR not a bigger plan402 INSUFFICIENT_FUNDS5xx PROVIDER_ERROR refunded