Аутентификация
Все API-запросы требуют аутентификации с помощью API-ключа. Передавайте ключ в заголовке Authorization как Bearer-токен. API-ключ должен начинаться с префикса nxd_.
Требования к тарифу: REST API, API, совместимый с ISPmanager, и вебхуки доступны на тарифе Про и выше – как и две возможности, которые тоже описаны в этом справочнике: DNSSEC и вторичные (slave) зоны. Ключ на тарифе без них получает ответ 403.
Authorization: Bearer nxd_your_api_key_here
API работает без сохранения состояния – каждый запрос аутентифицируется независимо. Сессии и cookies не используются.
Храните API-ключ в секрете. Не передавайте его в клиентском коде, публичных репозиториях или URL-адресах. Если ключ скомпрометирован, немедленно отзовите его и создайте новый.
Ошибки аутентификации
| Статус | Причина |
|---|---|
401 |
Отсутствующий или недействительный API-ключ, истёкший ключ или отменённый аккаунт |
403 |
У ключа нет разрешения, которое требует эндпоинт, либо тариф аккаунта не включает доступ к API – проверка тарифа отвечает 403, а не 401, на любом пути. |
Формат ответа
Все ответы возвращаются в формате JSON. Успешные ответы имеют следующую структуру:
Единичный ресурс
{
"status": "success",
"data": {
"id": "xK9mQ2",
"name": "example.com",
...
}
}
Список с пагинацией
{
"status": "success",
"data": [ ... ],
"meta": {
"total": 150,
"page": 1,
"per_page": 25,
"last_page": 6
}
}
Ответ с ошибкой
{
"status": "error",
"error": {
"code": "validation_error",
"message": "Validation failed.",
"details": {
"name": ["Domain name is required."]
}
}
}
Ошибки, возникающие глубже в платформе – лимит тарифа, заблокированный домен, недоступность DNS-серверов – содержат тот же объект error, но без поля status. Ветвите логику по error.code: он стабилен, в отличие от наличия поля status. Сообщения по контракту всегда на английском, на любом экземпляре и в любой локали; машиночитаемая часть – это error.code.
Публичные ID
Каждый ресурс идентифицируется непрозрачным id (например, xK9mQ2), который используется в URL-путях. Числовые ID из базы данных никогда не раскрываются и не принимаются.
Пагинация
Эндпоинты списков, возвращающие постраничные результаты, принимают следующие параметры запроса:
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
page |
integer | 1 | Номер страницы (минимум 1) |
per_page |
integer | 25 | Элементов на странице (1–100) |
Лимиты запросов
Запросы считаются на аккаунт, а не на ключ, в скользящем окне длиной одну минуту; размер лимита определяется тарифом – точное значение есть в сравнении тарифов на странице цен. Запросы без аутентификации считаются по IP-адресу. Текущее состояние лимита возвращается в каждом ответе, поэтому угадывать не нужно:
| Заголовок | Значение |
|---|---|
X-RateLimit-Limit | Сколько запросов разрешено в окне. |
X-RateLimit-Remaining | Сколько запросов осталось в текущем окне. |
X-RateLimit-Reset | Unix-время, когда начинается новое окно. |
Retry-After | Сколько секунд подождать; передаётся в ответе 429. |
При массовых операциях – импорте большой зоны, сверке сотен записей – читайте X-RateLimit-Remaining и делайте паузу до того, как счётчик дойдёт до нуля, вместо повторов после 429. CLI делает это за вас.
У некоторых операций поверх лимита запросов есть собственное, более длинное окно: одну зону можно перенести в другую группу DNS-серверов три раза в сутки. В ответе указано, какой лимит исчерпан.
Зоны
Управление DNS-зонами. Требуется zones.read для операций чтения и zones.write для операций записи.
GET /v1/zones
Список всех зон аутентифицированного пользователя.
Параметры запроса
search– фильтрация зон по имениpage,per_page– пагинация
Поля ответа
id, name, type (master или slave), status, ns_group, created_at, updated_at
GET /v1/zones/{id}
Получение подробной информации о конкретной зоне, включая SOA-данные, серверы имён и количество записей.
Дополнительные поля ответа
records_count, soa (primary_ns, admin_email, serial, refresh, retry, expire, minimum), nameservers (массив), ns_group (id, slug, name)
POST /v1/zones
Создание новой DNS-зоны. Отклоняется с кодом 409, если домен уже существует или пересекается с зоной другого аккаунта, и с кодом 422, если достигнут лимит зон тарифа или домен заблокирован.
Тело запроса (JSON)
{
"name": "example.com",
"type": "master",
"ns_group": "eu"
}
Вторичная (slave) зона:
{
"name": "example.com",
"type": "slave",
"master_ip": "203.0.113.10"
}
name(обязательно) – доменное имяtype–"master"(по умолчанию) или"slave"ns_group– группа NS для назначения зоны (необязательно, используется группа по умолчанию)master_ip– обязательно для вторичных (slave) зон; должен быть корректным публичным IP-адресом
Возвращает 201 Created с объектом зоны.
PATCH /v1/zones/{id}
Перенос зоны в другую группу DNS-серверов. Это единственный PATCH в API. Разрешение: zones.write.
Тело запроса (JSON)
{
"ns_group": "ru"
}
Возвращает зону в состоянии после переноса, в том же формате, что и GET /v1/zones/{id}. Группа указывается по её slug – это значения, которые перечисляет для вашего аккаунта GET /v1/ns-groups; любое другое значение отклоняется с кодом 400.
Зона продолжает отвечать всё время переноса: новые DNS-серверы готовятся до отправки ответа, а прежние обслуживают запросы, пока обновляются кеши резолверов. После переноса обновите делегирование у регистратора. Зону можно перенести три раза в сутки; сверх этого запрос вернёт 429.
DELETE /v1/zones/{id}
Удаление зоны и всех её записей.
Возвращает 204 No Content при успехе.
GET /v1/zones/{id}/export
Экспорт зоны в формате BIND или в структурированном JSON.
Параметры запроса
format–"bind"(по умолчанию) возвращает текст зонного файла BIND;"json"возвращает структурированный массив записей с полями name, type, content и ttl
Записи
Управление DNS-записями в зоне. Все эндпоинты записей вложены в зону. Требуется records.read для операций чтения и records.write для операций записи.
GET /v1/zones/{zoneId}/records
Список всех записей в зоне.
Параметры запроса
type– фильтрация по типу записи (например,A,CNAME,MX)name– фильтрация по имени записи (поиск подстроки)search– поиск по имени и содержимому
Поля ответа
id, name, type, content, ttl, disabled, fields (специфичные для типа поля)
GET /v1/zones/{zoneId}/records/{recordId}
Получение одной записи по её ID.
POST /v1/zones/{zoneId}/records
Создание новой DNS-записи.
Тело запроса (JSON)
{
"type": "A",
"name": "www",
"ttl": 3600,
"content": "93.184.216.34"
}
type(обязательно) – тип записи (A, AAAA, CNAME, MX, TXT, SRV, CAA, NS, PTR, ALIAS, DNAME, DS, TLSA)name– имя записи относительно зоны (по умолчанию:@– вершина зоны)ttl– время жизни в секундах (по умолчанию: 3600)content– значение записи (IP для A/AAAA, имя хоста для CNAME/NS/PTR, текст для TXT, почтовый сервер для MX)
Поля для конкретных типов
- MX:
priority(по умолчанию: 10) - SRV: поля
priority,weight,port - CAA:
flags(по умолчанию: 0),tag(по умолчанию: "issue") - DS: поля
keytag,algorithm,digest_type - TLSA: поля
usage,selector,matching_type
Для MX, SRV, CAA, DS и TLSA в content передаётся только основное значение – почтовый хост, цель SRV, домен удостоверяющего центра, сам hex-отпечаток – всё остальное указывается в полях выше. Собранная вручную строка записи (например, 0 issue "letsencrypt.org" в качестве content для CAA) отклоняется с кодом 400 и указанием поля.
TTL относится ко всему набору записей. Если вы добавляете ещё одно значение к уже существующему имени и не передаёте ttl, текущий TTL сохраняется; если передаёте – он применяется ко всем значениям этого имени. Для нового имени по умолчанию 3600 секунд.
Возвращает 201 Created с объектом записи.
PUT /v1/zones/{zoneId}/records/{recordId}
Обновление существующей записи. Укажите только поля, которые хотите изменить; остальные сохранят текущие значения.
{
"content": "93.184.216.35",
"ttl": 7200
}
Возвращает 200 OK с обновлённым объектом записи. Примечание: ID записи может измениться после обновления, так как он вычисляется из имени, типа и содержимого записи.
DELETE /v1/zones/{zoneId}/records/{recordId}
Удаление записи из зоны.
Возвращает 204 No Content при успехе.
DNSSEC
Управление DNSSEC для ваших зон. Требуется zones.read для просмотра статуса и zones.write для включения или отключения.
GET /v1/zones/{id}/dnssec
Получение статуса DNSSEC для зоны, включая ключи и DS-записи.
Поля ответа
enabled (boolean), keys (массив DNSKEY-записей), ds_records (массив DS-записей для установки у регистратора)
POST /v1/zones/{id}/dnssec/enable
Включение DNSSEC для зоны. Ключи подписи генерируются автоматически.
Возвращает статус DNSSEC с сгенерированными ключами и DS-записями.
POST /v1/zones/{id}/dnssec/disable
Отключение DNSSEC для зоны. Удаляет все ключи подписи.
Возвращает {"enabled": false, "keys": [], "ds_records": []}.
NS-группы
Список доступных групп DNS-серверов. Используйте id группы как ns_group при создании зоны. Эндпоинт доступен по любому действующему API-ключу.
GET /v1/ns-groups
Список активных групп DNS-серверов.
Поля ответа для каждой группы
id, name, slug
Аккаунт
Просмотр информации об аккаунте и управление API-ключами.
GET /v1/account
Получение информации о текущем аккаунте, включая данные подписки.
Поля ответа
Поля id (UUID), email, name, role, status, language, timezone, created_at.
subscription – объект с полями plan, billing_cycle, status, current_period_start, current_period_end (или null при отсутствии подписки)
GET /v1/account/api-keys
Список всех API-ключей аутентифицированного пользователя.
Поля ответа для каждого ключа
id, name, key_prefix (первые 8 символов), permissions (массив), last_used_at, expires_at, created_at
POST /v1/account/api-keys
Создание нового API-ключа.
Тело запроса (JSON)
{
"name": "CI/CD Pipeline",
"permissions": ["zones.read", "records.read", "records.write"],
"expires_at": "2027-01-01"
}
name(обязательно) – понятное имя (максимум 255 символов)permissions(обязательно) – массив разрешений (минимум одно):zones.read,zones.write,records.read,records.write,webhooks.read,webhooks.writeexpires_at– необязательная дата истечения (ISO 8601 илиYYYY-MM-DD); должна быть в будущем
Ответ содержит полный API-ключ в поле
key. Это единственный раз, когда полный ключ возвращается. Сохраните его в надёжном месте.
Возвращает 201 Created с данными ключа, включая полное значение key.
DELETE /v1/account/api-keys/{id}
Отзыв (безвозвратное удаление) API-ключа.
Возвращает 204 No Content при успехе.
Биллинг
Просмотр подписки, тарифных планов и счетов. Эти эндпоинты доступны только для чтения.
GET /v1/billing/subscription
Получение данных текущей подписки. Возвращает null при отсутствии активной подписки.
Поля ответа
Поля id, plan, billing_cycle, status, current_period_start, current_period_end, created_at.
GET /v1/billing/plans
Список всех доступных тарифных планов с ценами и функциями.
Поля ответа для каждого плана
id, name, slug, description, price_monthly, price_yearly, currency, max_domains, max_records, features (массив)
GET /v1/billing/invoices
Список счетов аутентифицированного пользователя, сначала новые.
Параметры запроса
status– фильтрация по статусу (draft,issued,sent,void)page,per_page– пагинация
GET /v1/billing/invoices/{id}
Получение одного счёта по его <code>id</code>.
Поля ответа
Поля id, number, status, amount (итоговая сумма), net_amount (без налога), tax_amount, tax_rate, currency, issued_at, created_at. Денежные значения передаются строками с десятичной точкой.
Webhooks
Управление исходящими webhook-подписками для получения уведомлений об изменениях зон и записей в реальном времени. Требует webhooks.read для чтения и webhooks.write для создания, изменения и удаления.
GET /v1/webhooks
Список всех webhook-подписок аутентифицированного пользователя.
Поля ответа для каждой подписки
id, url, events (массив), description, is_active, failure_count, last_triggered_at, created_at
POST /v1/webhooks
Создание webhook-подписки.
Тело запроса (JSON)
{
"url": "https://example.com/webhook",
"events": ["zone.created", "record.created"],
"description": "Production webhook"
}
url(обязательно) – HTTPS-адрес, на который будут отправляться данные событийevents(обязательно) – массив типов событий для подпискиdescription– необязательная понятная метка
Ответ содержит
secretдля проверки подписи webhook (HMAC). Это единственный раз, когда secret возвращается. Сохраните его в надёжном месте.
Возвращает 201 Created с id и secret подписки.
GET /v1/webhooks/{id}
Получение одной webhook-подписки вместе с последними доставками.
PUT /v1/webhooks/{id}
Изменение webhook-подписки. Указывайте только те поля, которые нужно изменить.
Возвращает 200 OK с обновлённым объектом подписки.
DELETE /v1/webhooks/{id}
Удаление webhook-подписки.
Возвращает 204 No Content при успехе.
POST /v1/webhooks/{id}/test
Отправка тестового события на адрес webhook для проверки доступности.
Ставит в очередь тестовую доставку с данными "type": "test".
Проверка доставки
Каждая доставка подписывается секретом, который возвращается при создании подписки, и содержит четыре заголовка:
X-NexDNS-Signature: sha256=<hmac>
X-NexDNS-Timestamp: 1785370265
X-NexDNS-Event: record.created
X-NexDNS-Delivery: 42
Вычислите HMAC-SHA256 по телу запроса в исходном виде, используя свой секрет, и сравните результат с hex-отпечатком после sha256= – сравнением за постоянное время. Несовпадение означает, что запрос пришёл не от нас. Заголовок X-NexDNS-Delivery идентифицирует попытку: повторные доставки одного события имеют одинаковый id события, но разные номера доставки.
Данные доставки
{
"id": "evt_szpj9u04z8u0",
"type": "record.created",
"created_at": "2026-07-30 00:31:05",
"data": {
"zone": { "name": "example.com" },
"record": { "name": "www.example.com.", "type": "A", "content": "203.0.113.10", "ttl": 3600 }
}
}
Доступные типы событий
Можно подписаться на любую комбинацию этих типов событий:
zone.created, zone.updated, zone.deleted, record.created, record.updated, record.deleted, dnssec.enabled, dnssec.disabled, zone.health.problem, zone.health.resolved
Коды ошибок
Все ошибки имеют единый формат со строковым code ошибки и понятным message.
| HTTP-статус | Код ошибки | Описание |
|---|---|---|
400 |
validation_error |
Тело запроса не прошло валидацию. Проверьте details для ошибок по отдельным полям. |
401 |
unauthorized |
Отсутствующий, недействительный или истёкший API-ключ. |
403 |
forbidden |
У API-ключа нет нужного разрешения, тариф аккаунта не включает доступ к API, либо тариф не включает используемую возможность (например, вторичные зоны или DNSSEC). |
404 |
not_found |
Запрашиваемый ресурс не существует или недоступен для аутентифицированного пользователя. |
409 |
conflict |
Ресурс уже существует (например, дубликат имени зоны). |
422 |
quota_exceeded |
Достигнут лимит зон или записей вашего тарифа. |
422 |
domain_blacklisted |
Домен находится в списке заблокированных, добавить его нельзя. |
429 |
rate_limit_exceeded |
Слишком много запросов. Проверьте заголовок Retry-After. |
500 |
server_error |
Произошла непредвиденная внутренняя ошибка. Повторите попытку или обратитесь в поддержку, если она повторяется. |
502 |
dns_server_error |
DNS-серверы временно недоступны. Запрос не применён, повторите его. |
Примеры кода
Все примеры используют curl. Замените nxd_your_api_key на ваш настоящий API-ключ.
Список зон
curl -s "https://api.nexdns.ru/v1/zones" \
-H "Authorization: Bearer nxd_your_api_key"
Создание зоны
curl -s -X POST "https://api.nexdns.ru/v1/zones" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"name": "example.com"}'
Добавление A-записи
curl -s -X POST "https://api.nexdns.ru/v1/zones/{zoneId}/records" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "A",
"name": "www",
"ttl": 3600,
"content": "93.184.216.34"
}'
Добавление MX-записи
curl -s -X POST "https://api.nexdns.ru/v1/zones/{zoneId}/records" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "MX",
"name": "@",
"ttl": 3600,
"content": "mail.example.com",
"priority": 10
}'
Обновление записи
curl -s -X PUT "https://api.nexdns.ru/v1/zones/{zoneId}/records/{recordId}" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"content": "93.184.216.35", "ttl": 7200}'
Удаление записи
curl -s -X DELETE "https://api.nexdns.ru/v1/zones/{zoneId}/records/{recordId}" \
-H "Authorization: Bearer nxd_your_api_key"
Экспорт зоны (формат BIND)
curl -s "https://api.nexdns.ru/v1/zones/{zoneId}/export" \
-H "Authorization: Bearer nxd_your_api_key"
Включение DNSSEC
curl -s -X POST "https://api.nexdns.ru/v1/zones/{zoneId}/dnssec/enable" \
-H "Authorization: Bearer nxd_your_api_key"
Создание API-ключа
curl -s -X POST "https://api.nexdns.ru/v1/account/api-keys" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Read-only key",
"permissions": ["zones.read", "records.read"],
"expires_at": "2027-12-31"
}'
Информация об аккаунте
curl -s "https://api.nexdns.ru/v1/account" \
-H "Authorization: Bearer nxd_your_api_key"