Void API — твои домены по REST.
Проверка доступности, регистрация и продление, смена nameservers, подключение домена к Cloudflare и управление его DNS, защитными переключателями и редиректами — из своего кода, на том же аккаунте и балансе, что и бот.
Быстрый старт
пять вызовов от нуля до живого доменаВ Telegram-боте: профиль → API → создать ключ. Показывается один раз — храни в секретах, не в коде.
GET /domains/check?domain=… — сверка с реестром и точная цена, которую спишем.
POST /domains — списывается баланс, домен встаёт на наши nameservers со страницей парковки.
POST /domains/{id}/cloudflare — зона создана, nameservers в реестре переключены за тебя.
POST /domains/{id}/dns — A-запись на твой сервер, через прокси или напрямую.
export VOID_KEY="void_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
API=https://api.voidhosting.org/v1
# 1. свободно ли и за сколько?
curl -s "$API/domains/check?domain=example.xyz" -H "Authorization: Bearer $VOID_KEY"
# 2. регистрация (списывает баланс, возвращает 201 + объект домена)
curl -s -X POST "$API/domains" -H "Authorization: Bearer $VOID_KEY" \
-H "Content-Type: application/json" -d '{"domain":"example.xyz"}'
# 3. подключить Cloudflare и добавить A-запись
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}'const API = "https://api.voidhosting.org/v1";
const headers = { Authorization: `Bearer ${process.env.VOID_KEY}`, "Content-Type": "application/json" };
const call = async (method, path, body) => {
const r = await fetch(API + path, { method, headers, body: body && JSON.stringify(body) });
const j = await r.json();
if (!j.ok) throw new Error(`${j.error.code}: ${j.error.message}`);
return j.data;
};
const check = await call("GET", "/domains/check?domain=example.xyz");
if (check.available) {
const domain = await call("POST", "/domains", { domain: "example.xyz" });
await call("POST", `/domains/${domain.id}/cloudflare`);
await call("POST", `/domains/${domain.id}/dns`, { type: "A", name: "@", content: "203.0.113.10", proxied: true });
}import os, requests
API = "https://api.voidhosting.org/v1"
H = {"Authorization": f"Bearer {os.environ['VOID_KEY']}"}
def call(method, path, **body):
r = requests.request(method, API + path, headers=H, json=body or None, timeout=30).json()
if not r["ok"]:
raise RuntimeError(f"{r['error']['code']}: {r['error']['message']}")
return r["data"]
check = call("GET", "/domains/check?domain=example.xyz")
if check["available"]:
domain = call("POST", "/domains", domain="example.xyz")
call("POST", f"/domains/{domain['id']}/cloudflare")
call("POST", f"/domains/{domain['id']}/dns", type="A", name="@", content="203.0.113.10", proxied=True)Пример: от покупки до A-записи
все запросы и ответы одного реального сценарияОдин домен от начала до конца: проверка → регистрация → подключение Cloudflare → ожидание зоны → записи → SSL. Ответы сокращены только там, где стоит …. Один раз задай H='Authorization: Bearer void_…' — он нужен в каждом вызове.
1 · Свободно?
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 · Регистрация
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": [] } }
# баланс: 25.07 → 17.07; имя уже резолвится на нашу страницу парковки3 · Подключаем 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: реестр уже смотрит на Cloudflare; zoneStatus станет "active", когда Cloudflare это увидит4 · Записи можно добавлять сразу (ждать "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 · Ждём, пока зона станет активной
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 } }
# обычно 2–20 минут после шага 36 · SSL и переключатели
# на сервере ещё нет сертификата → flexible; когда появится — переключи на "full"/"strict"
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 · Проверяем результат
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 # IP Cloudflare — исходный сервер скрытЧто может пойти не так: шаг 2 → 409 DOMAIN_UNAVAILABLE (кто-то успел раньше) или 402 INSUFFICIENT_FUNDS; шаг 3 → 503 CLOUDFLARE_NO_ACCOUNTS (повтори через пару минут); шаг 6 до активации зоны → 409 CLOUDFLARE_ZONE_PENDING. Ничего откатывать руками не нужно: неудавшиеся платные вызовы возвращают деньги сами.
Аутентификация
Каждый вызов несёт API-ключ как bearer-токен. Ключ принадлежит аккаунту, а не человеку: кто им владеет, тот может тратить баланс и менять домены. До 5 ключей на аккаунт, каждый отзывается отдельно — по ключу на интеграцию будет правильно.
Authorization: Bearer void_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxЖизненный цикл
- Создать — бот → профиль → API → создать ключ. Открытый текст показывается один раз и у нас не хранится (только хеш).
- Посмотреть — там же список ключей по префиксу (
void_cT4dmZf…) с датой создания и последнего вызова. - Отозвать — удалить на том же экране; со следующего запроса ключ отвечает
401.
Ключ не нужен для GET /v1 (индекс ресурсов) и документации. Всё остальное без ключа отвечает 401 UNAUTHORIZED. Только HTTPS — HTTP редиректится до того, как дойдёт до API.
Соглашения
одни правила вездеКонверт
{ "ok": true, "data": … }
{ "ok": false, "error": { "code": "…", "message": "…", "details": … } }HTTP-статусы
200 ок
201 создано (POST /domains, cloudflare, dns, redirects)
4xx на твоей стороне — смотри код ошибки
5xx наша или внешняя — можно повторить позжеТипы
| что | формат | пример |
|---|---|---|
| деньги | десятичная строка, USD, 2 знака — никогда не float | "14.50" |
| время | ISO 8601, UTC | "2027-08-28T17:04:38.000Z" |
| идентификаторы | UUID v4 для наших объектов; собственные id Cloudflare для DNS-записей и редиректов | "0a797218-8ec5-…" |
| имена доменов | нормализуются к регистрируемой форме, нижний регистр, без www. | Example.COM → example.com |
| списки | offset / limit (макс. 100) в query; items + total в ответе | ?offset=20&limit=20 |
Вызовы, которые списывают деньги
POST /domains и POST /domains/{id}/renew списывают баланс сразу. Если реестр затем откажет, списание отменяется автоматически — за неудавшуюся операцию ты не платишь. Баланс пополняется в боте; в API деньги только на чтение.
Повторы и идемпотентность
Чтение можно повторять свободно. Повторный POST /domains с тем же именем после успешной покупки вернёт 409 DOMAIN_UNAVAILABLE, так что купить домен дважды нельзя. После таймаута GET /domains покажет, прошёл ли заказ, прежде чем повторять.
Ошибки
Коды ошибок — стабильные строки, на которые можно завязываться; message для людей и может меняться. details присутствует, когда есть что сказать структурно (ошибки валидации, недостающая сумма).
| HTTP | код | значение |
|---|---|---|
| 400 | VALIDATION_ERROR | кривой запрос; в details[] — path и message по каждому полю |
| 400 | DOMAIN_INVALID | это не доменное имя |
| 401 | UNAUTHORIZED | ключ отсутствует, неизвестен или отозван |
| 402 | INSUFFICIENT_FUNDS | не хватает баланса; details = { required, balance, missing } |
| 403 | USER_BANNED | аккаунт заблокирован |
| 404 | DOMAIN_NOT_FOUND · DNS_NOT_FOUND · NOT_FOUND | нет на этом аккаунте / нет такого эндпоинта |
| 409 | DOMAIN_UNAVAILABLE | занят, премиум или зона, которую мы не продаём |
| 409 | CLOUDFLARE_ALREADY · CLOUDFLARE_NOT_CONNECTED · CLOUDFLARE_ZONE_PENDING | состояние зоны не позволяет операцию |
| 409 | DNS_EXISTS · REDIRECT_EXISTS · REDIRECT_LIMIT | дубликат или достигнут лимит |
| 429 | RATE_LIMITED | превышен лимит на ключ — сбавь темп |
| 502 | REGISTRAR_ERROR · CLOUDFLARE_ERROR | внешний сервис упал; повтори позже, деньги не списаны |
| 503 | CLOUDFLARE_UNAVAILABLE · CLOUDFLARE_NO_ACCOUNTS | временно нет мощности |
{ "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" } } }Лимиты
При превышении — 429 RATE_LIMITED; подожди несколько секунд и повтори. Проверки доступности идут в реестр в реальном времени — кешируй ответы у себя на несколько минут вместо опроса и предпочитай /domains/search (один вызов, все зоны) множеству одиночных проверок.