Void API — your domains, over REST.

Check availability, register and renew, switch nameservers, put a domain behind Cloudflare and manage its DNS, security switches and redirects — from your own code, on the same account and balance as the bot.

https://api.voidhosting.org/v1 Bearer void_… JSON · UTC · USD strings

Quickstart

five calls from zero to a live domain
Create a key

In the Telegram bot: profile → API → create a key. It is shown once — keep it in a secret store, not in code.

Check a name

GET /domains/check?domain=… — verified against the registry, with the exact price you will pay.

Register

POST /domains — the balance is charged, the name lands on our nameservers with a parking page.

Connect Cloudflare

POST /domains/{id}/cloudflare — zone created, nameservers switched at the registry for you.

Point it somewhere

POST /domains/{id}/dns — an A record to your server, proxied or not.

export VOID_KEY="void_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
API=https://api.voidhosting.org/v1

# 1. is it free, and for how much?
curl -s "$API/domains/check?domain=example.xyz" -H "Authorization: Bearer $VOID_KEY"

# 2. register (charges the balance, returns 201 + the domain object)
curl -s -X POST "$API/domains" -H "Authorization: Bearer $VOID_KEY" \
  -H "Content-Type: application/json" -d '{"domain":"example.xyz"}'

# 3. connect Cloudflare, then add an A record
curl -s -X POST "$API/domains/$ID/cloudflare" -H "Authorization: Bearer $VOID_KEY"
curl -s -X POST "$API/domains/$ID/dns" -H "Authorization: Bearer $VOID_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"A","name":"@","content":"203.0.113.10","proxied":true}'

Example: from purchase to an A record

every request and response of one real flow

One domain, start to finish: check → register → connect Cloudflare → wait for the zone → add records → tighten SSL. Responses are shortened only where marked …. Set H='Authorization: Bearer void_…' once; every call carries it.

1 · Is it free?

curl -s "https://api.voidhosting.org/v1/domains/check?domain=steamgaloshi.world" -H "$H"

{ "ok": true, "data": { "domain": "steamgaloshi.world", "available": true, "price": "8.00" } }

2 · Register

curl -s -X POST https://api.voidhosting.org/v1/domains -H "$H" -H "Content-Type: application/json" \
  -d '{"domain":"steamgaloshi.world"}'

HTTP/2 201
{ "ok": true, "data": {
    "id": "6f1c2e0e-3f6a-4a4b-9a1d-8f5e9b2c7d10", "domainName": "steamgaloshi.world", "status": "ACTIVE",
    "nameservers": ["ns1.voidhosting.org", "ns2.voidhosting.org"],
    "price": "8.00", "renewalPrice": "8.00", "renewalYears": 1, "autoRenew": false,
    "expiresAt": "2027-08-31T19:45:54.000Z", "createdAt": "2026-08-31T19:45:50.714Z", "blockFlags": [] } }
# the balance went 25.07 → 17.07; the name already resolves to our parking page

3 · Connect Cloudflare

ID=6f1c2e0e-3f6a-4a4b-9a1d-8f5e9b2c7d10
curl -s -X POST https://api.voidhosting.org/v1/domains/$ID/cloudflare -H "$H"

HTTP/2 201
{ "ok": true, "data": { "connected": true, "domainName": "steamgaloshi.world", "zoneId": "9b3e…",
    "nameservers": ["ada.ns.cloudflare.com", "kip.ns.cloudflare.com"], "zoneStatus": "pending", "nsApplied": true } }
# nsApplied: the registry already points at Cloudflare; zoneStatus turns "active" when Cloudflare notices

4 · Add records right away (no need to wait for "active")

curl -s -X POST https://api.voidhosting.org/v1/domains/$ID/dns -H "$H" -H "Content-Type: application/json" \
  -d '{"type":"A","name":"@","content":"203.0.113.10","proxied":true}'

HTTP/2 201
{ "ok": true, "data": { "id": "a1f0…", "type": "A", "name": "steamgaloshi.world", "content": "203.0.113.10", "proxied": true, "priority": null } }

curl -s -X POST https://api.voidhosting.org/v1/domains/$ID/dns -H "$H" -H "Content-Type: application/json" \
  -d '{"type":"CNAME","name":"www","content":"steamgaloshi.world","proxied":true}'

HTTP/2 201
{ "ok": true, "data": { "id": "b7c2…", "type": "CNAME", "name": "www.steamgaloshi.world", "content": "steamgaloshi.world", "proxied": true, "priority": null } }

5 · Poll the zone until it is active

until curl -s -X POST https://api.voidhosting.org/v1/domains/$ID/cloudflare/refresh -H "$H" | grep -q '"zoneStatus":"active"'; do sleep 60; done

{ "ok": true, "data": { "connected": true, "domainName": "steamgaloshi.world", "zoneId": "9b3e…",
    "nameservers": ["ada.ns.cloudflare.com", "kip.ns.cloudflare.com"], "zoneStatus": "active", "nsApplied": true } }
# typically 2–20 minutes after step 3

6 · SSL and switches

# the origin has no certificate yet → flexible; switch to "full"/"strict" once it does
curl -s -X PATCH https://api.voidhosting.org/v1/domains/$ID/cloudflare/settings -H "$H" -H "Content-Type: application/json" \
  -d '{"ssl":"flexible","botFightMode":true,"alwaysOnline":true}'

{ "ok": true, "data": { "ssl": "flexible", "developmentMode": false, "underAttack": false, "alwaysOnline": true, "botFightMode": true, "regionBlock": false } }

7 · Check the result

curl -s https://api.voidhosting.org/v1/domains/$ID/dns -H "$H"

{ "ok": true, "data": [
    { "id": "a1f0…", "type": "A",     "name": "steamgaloshi.world",     "content": "203.0.113.10",       "proxied": true, "priority": null },
    { "id": "b7c2…", "type": "CNAME", "name": "www.steamgaloshi.world", "content": "steamgaloshi.world", "proxied": true, "priority": null } ] }

dig +short steamgaloshi.world        # Cloudflare edge IPs — the origin stays hidden

What can go wrong along the way: step 2 → 409 DOMAIN_UNAVAILABLE (someone was faster) or 402 INSUFFICIENT_FUNDS; step 3 → 503 CLOUDFLARE_NO_ACCOUNTS (retry in a few minutes); step 6 before the zone is active → 409 CLOUDFLARE_ZONE_PENDING. Nothing in this flow needs to be undone by hand: failed money-moving calls refund themselves.

Authentication

Every call carries an API key as a bearer token. Keys belong to your account, not to a person: whoever holds one can spend the balance and change your domains. Up to 5 keys per account, each revocable on its own — one per integration is a good habit.

Authorization: Bearer void_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Lifecycle

  • Create — bot → profile → API → create a key. The plaintext is shown once and never stored on our side (only a hash).
  • Inspect — the same screen lists keys by prefix (void_cT4dmZf…) with creation and last-use time.
  • Revoke — delete from the screen; the key fails with 401 on the next request.

No key is needed for GET /v1 (an index of resources) and the docs. Everything else answers 401 UNAUTHORIZED without one. HTTPS only — HTTP is redirected before it reaches the API.

Conventions

the same rules everywhere

Envelope

{ "ok": true,  "data": … }
{ "ok": false, "error": { "code": "…", "message": "…", "details": … } }

Status codes

200  ok
201  created (POST /domains, cloudflare, dns, redirects)
4xx  your side — see the error code
5xx  ours or upstream — safe to retry later

Types

kindformatexample
moneydecimal string, USD, 2 places — never a float"14.50"
timeISO 8601, UTC"2027-08-28T17:04:38.000Z"
idsUUID v4 for our objects; Cloudflare's own ids for DNS records and redirects"0a797218-8ec5-…"
domain namesnormalised to the registrable form, lowercase, no www.Example.COM → example.com
listsoffset / limit (max 100) in the query; items + total in the response?offset=20&limit=20

Money-moving calls

POST /domains and POST /domains/{id}/renew charge the account balance immediately. If the registry then refuses the order, the charge is reversed automatically — you never pay for a failed operation. Balance is topped up in the bot; the API is read-only about money.

Retries & idempotency

Reads are safe to retry. A repeated POST /domains for the same name fails with 409 DOMAIN_UNAVAILABLE once the first attempt succeeded, so a retry cannot buy the same domain twice. On a timeout, GET /domains tells you whether the order went through before you try again.

Errors

Error codes are stable strings you can switch on; message is for humans and may change. details is present when there is something structured to say (validation issues, the missing amount).

HTTPcodemeaning
400VALIDATION_ERRORmalformed request; details[] has path and message per field
400DOMAIN_INVALIDnot a valid domain name
401UNAUTHORIZEDmissing, unknown or revoked key
402INSUFFICIENT_FUNDSbalance too low; details = { required, balance, missing }
403USER_BANNEDaccount suspended
404DOMAIN_NOT_FOUND · DNS_NOT_FOUND · NOT_FOUNDnot on this account / no such endpoint
409DOMAIN_UNAVAILABLEtaken, premium, or a zone we do not sell
409CLOUDFLARE_ALREADY · CLOUDFLARE_NOT_CONNECTED · CLOUDFLARE_ZONE_PENDINGzone state does not allow the operation
409DNS_EXISTS · REDIRECT_EXISTS · REDIRECT_LIMITduplicate or limit reached
429RATE_LIMITEDover the per-key limit — back off
502REGISTRAR_ERROR · CLOUDFLARE_ERRORupstream failed; retry later, nothing was charged
503CLOUDFLARE_UNAVAILABLE · CLOUDFLARE_NO_ACCOUNTStemporarily out of capacity
{ "ok": false, "error": { "code": "INSUFFICIENT_FUNDS", "message": "account balance is too low — top up in the bot",
    "details": { "required": "16.00", "balance": "5.50", "missing": "10.50" } } }

Rate limits

120 requests / minute per key20 / minute for check · search · registersliding window

Over the limit you get 429 RATE_LIMITED; wait a few seconds and retry. Availability checks go to the registry in real time — cache answers on your side for a few minutes instead of polling, and prefer /domains/search (one call, all zones) over many single checks.

support news voidhosting.org Void · api v1