Skip to content

Отправить ЭЦП и создать попытку проверки владельца ​

POST /domains/{domainUuid}/registrant-verification

operationId: submitRegistrantVerification

Требуемые scopes: domains.verify.

Сначала получите свежий payload. Передайте payload_snapshot, точный signable_payload и signature_options без изменений, signature = Base64 DER detached CMS CAdES-T с меткой времени. Проверяются криптография, доверие, отзыв и соответствие ИИН/БИН/полномочий владельцу; специальная политика ИП для .edu.kz не отменяет криптопроверку. Невалидный тип подписи, CMS, mismatch документа или отказ регистратора может создать Verification со status=failed и HTTP 201, а не HTTP 422. HTTP 422 означает ошибку HTTP-валидации либо запрет новой попытки (pending/already verified/конкурентная обработка). Проверяйте data.status и failure_message; отдельный failure_code ресурс не выдаёт. Для pending ждите реестр, новую подпись не отправляйте; если ожидание затянулось, обращайтесь в поддержку. Отказ по образовательной лицензии независим от действительности ЭЦП. JSON-пример полный, но содержит демонстрационный идентификатор и НЕ настоящую подпись; подпись всегда формируется на устройстве владельца по свежему документу.

Обязателен Idempotency-Key (1..160 символов). Повтор с тем же ключом должен сохранять метод, путь, query и точные байты JSON. HTTP replay обычно хранится 24 часа и возвращает первоначальный ответ, а не актуальную задачу; проверяйте GET /operations/{operationUuid}. Ключ доменной задачи нельзя переиспользовать после истечения HTTP TTL.

Лимит общий для всех запросов одного API-ключа (rate_limit_per_minute, значение по умолчанию при выдаче ключа 120, индивидуальное значение может отличаться). Окно счётчика 60 секунд. Учитывайте X-RateLimit-Limit и X-RateLimit-Remaining; при 429 дождитесь Retry-After секунд и добавьте jitter. Polling и повторы также расходуют лимит; лимиты реестра независимы.

Scopes: domains.verify

x-input-caveats:

json
[
  "Передавайте синтаксически корректный UUID. Не все методы выполняют явную UUID-валидацию до SQL; поведение malformed UUID не унифицировано и в PostgreSQL может дать 500 вместо 404/422. Это ограничение реализации, не рекомендуемый сценарий клиента."
]

Параметры ​

domainUuid ​

Расположение: path. Обязательный. UUID из ответа API. Передавайте корректную строку UUID. Ресурс другого реселлера или среды не раскрывается.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Idempotency-Key ​

Расположение: header. Обязательный. Обязателен для POST/PUT/PATCH/DELETE, включая check, sync, test, rotate-secret. После trim 1..160 символов. Один ключ на логическую операцию и API-ключ. Повторите те же method/path/query и байты JSON. TTL HTTP replay по умолчанию 24 часа от первого резервирования; не продлевается. Не переиспользуйте ключ для новой операции, доменная задача дополнительно сохраняет связь с ним.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаminLength: 1; maxLength: 160

Пример

json
"webhook-create-20261005-0001"

Тело запроса ​

Обязательное. JSON body; Content-Type: application/json.

application/json ​

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["type","payload_snapshot","signable_payload"]Схема: DomainVerificationRequest
$.typestringДаmaxLength: 80На уровне HTTP принимается строка до 80; фактически поддерживается только eds. Другой тип создаёт failed Verification.
$.payload_snapshotobjectДаrequired: ["domain-name","domain-creation-time","registrant-name","registrant-org","registrant-residencedetails-country","registrant-residencedetails-externalidtype","registrant-residencedetails-externalidvalue"]Сервер HTTP проверяет array; успешная бизнес-проверка требует точные семь ключей из GET. Не добавляйте/не удаляйте поля. Схема: DomainVerificationSnapshot
$.payload_snapshot.domain-namestringДаТочное имя из реестра, Punycode.
$.payload_snapshot.domain-creation-timestring / nullДаДата создания в EPP, сохраняйте исходную строку.
$.payload_snapshot.registrant-namestring / nullДаИмя владельца из реестра/манифеста.
$.payload_snapshot.registrant-orgstring / nullДаОрганизация владельца либо null.
$.payload_snapshot.registrant-residencedetails-countrystring / nullДаСтрана резидентства.
$.payload_snapshot.registrant-residencedetails-externalidtypestring / nullДаТип документа, например IIN/BIN.
$.payload_snapshot.registrant-residencedetails-externalidvaluestring / nullДаЧувствительный идентификатор владельца; не логируйте.
$.signable_payloadstringДаСкопируйте полный signable_payload из свежего GET без изменений.
$.signaturestring / nullНетТолько записьBase64 DER detached CMS CAdES-T, обязательна при type=eds. Пример ниже не является действительной подписью.
$.certificatestring / nullНетТолько записьНеобязательный сертификат подписанта.
$.eds_providerstring / nullНетmaxLength: 80Идентификатор провайдера; рекомендуется ncalayer.
$.signature_optionsobjectНетHTTP-валидатор допускает неполный объект/nullable-поля. Для действительной EDS-проверки передайте ВСЕ восемь значений из signature_options GET; иначе возможен HTTP 201 со status=failed. Схема: DomainSignatureRequestOptions
$.signature_options.methodstring / nullНетmaxLength: 80Для действительной подписи строго kz.gov.pki.knca.basics.sign.
$.signature_options.formatstring / nullНетmaxLength: 20Для действительной подписи строго cms.
$.signature_options.decodeboolean / nullНетПодписываются исходные текстовые байты, не Base64-декодированный документ.
$.signature_options.encapsulateboolean / nullНетТолько detached CMS.
$.signature_options.digestedboolean / nullНетНе передавать предварительный дайджест вместо документа.
$.signature_options.timestamp_appliedboolean / nullНетНужна метка времени CAdES-T.
$.signature_options.cms_typestring / nullНетmaxLength: 80Для действительной подписи строго CMS Detached.
$.signature_options.cades_profilestring / nullНетmaxLength: 80Для действительной подписи строго CAdES-T.
$ (allOf 1)Условная схемаДа
$ (allOf 1) (if)objectДаrequired: ["type"]
$ (allOf 1) (if).typeУсловная схемаДаconst: "eds"
$ (allOf 1) (then)objectДаrequired: ["signature","signature_options"]
$ (allOf 1) (then).signaturestringДаminLength: 1
$ (allOf 1) (then).signature_optionsobjectДаminProperties: 1

Структура отправки; замените signature результатом подписи документа из GET ​

json
{
  "type": "eds",
  "payload_snapshot": {
    "domain-name": "example.kz",
    "domain-creation-time": "2026-10-01T08:00:00.000Z",
    "registrant-name": "Ivan Petrov",
    "registrant-org": null,
    "registrant-residencedetails-country": "KZ",
    "registrant-residencedetails-externalidtype": "IIN",
    "registrant-residencedetails-externalidvalue": "000000000000"
  },
  "signable_payload": "[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\n\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\n\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\n---------------------------------------------------------------------------\n* Домендік атау: example.kz\n* Құрылған күні: 2026-10-01T08:00:00.000Z\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\n* Ұйым: \n* Ел: KZ\n* Құжат түрі: IIN\n* Құжат нөмірі: 000000000000\n\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\n\nKazNIC. Барлық құқықтар қорғалған.\n\n\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\n\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\nказахстанского сегмента Интернета.\n\nДАННЫЕ ОПЕРАЦИИ:\n---------------------------------------------------------------------------\n* Доменное имя: example.kz\n* Дата создания: 2026-10-01T08:00:00.000Z\n* Регистрант (ФИО): Ivan Petrov\n* Организация: \n* Страна: KZ\n* Тип документа: IIN\n* Номер документа: 000000000000\n\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\n\nKazNIC. Все права защищены.",
  "signature": "REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER",
  "certificate": null,
  "eds_provider": "ncalayer",
  "signature_options": {
    "method": "kz.gov.pki.knca.basics.sign",
    "format": "cms",
    "decode": false,
    "encapsulate": false,
    "digested": false,
    "timestamp_applied": true,
    "cms_type": "CMS Detached",
    "cades_profile": "CAdES-T"
  }
}
bash
API_BASE_URL='https://api.b.websoft.kz/api/reseller/v1'
: "${RESELLER_API_TOKEN:?Set RESELLER_API_TOKEN in your environment}"
: "${DOMAIN_UUID:?Set DOMAIN_UUID}"
: "${IDEMPOTENCY_KEY:?Set one persisted unique key per logical request}"

curl --request POST "$API_BASE_URL/domains/${DOMAIN_UUID}/registrant-verification" \
  --connect-timeout 5 --max-time 20 --fail-with-body \
  --header "Authorization: Bearer $RESELLER_API_TOKEN" \
  --header 'Accept: application/json' \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --header 'Content-Type: application/json' \
  --data-raw '{
  "type": "eds",
  "payload_snapshot": {
    "domain-name": "example.kz",
    "domain-creation-time": "2026-10-01T08:00:00.000Z",
    "registrant-name": "Ivan Petrov",
    "registrant-org": null,
    "registrant-residencedetails-country": "KZ",
    "registrant-residencedetails-externalidtype": "IIN",
    "registrant-residencedetails-externalidvalue": "000000000000"
  },
  "signable_payload": "[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\n\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\n\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\n---------------------------------------------------------------------------\n* Домендік атау: example.kz\n* Құрылған күні: 2026-10-01T08:00:00.000Z\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\n* Ұйым: \n* Ел: KZ\n* Құжат түрі: IIN\n* Құжат нөмірі: 000000000000\n\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\n\nKazNIC. Барлық құқықтар қорғалған.\n\n\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\n\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\nказахстанского сегмента Интернета.\n\nДАННЫЕ ОПЕРАЦИИ:\n---------------------------------------------------------------------------\n* Доменное имя: example.kz\n* Дата создания: 2026-10-01T08:00:00.000Z\n* Регистрант (ФИО): Ivan Petrov\n* Организация: \n* Страна: KZ\n* Тип документа: IIN\n* Номер документа: 000000000000\n\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\n\nKazNIC. Все права защищены.",
  "signature": "REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER",
  "certificate": null,
  "eds_provider": "ncalayer",
  "signature_options": {
    "method": "kz.gov.pki.knca.basics.sign",
    "format": "cms",
    "decode": false,
    "encapsulate": false,
    "digested": false,
    "timestamp_applied": true,
    "cms_type": "CMS Detached",
    "cades_profile": "CAdES-T"
  }
}'
php
<?php
declare(strict_types=1);

// PHP 8.0+; extensions: curl, json. Persist the key/body before any write.
function requiredEnv(string $name): string
{
    $value = getenv($name);
    if ($value === false || $value === '' || str_contains($value, "\r") || str_contains($value, "\n")) {
        throw new RuntimeException('Set a valid environment variable: ' . $name);
    }
    return $value;
}

$baseUrl = rtrim(getenv('API_BASE_URL') ?: 'https://api.b.websoft.kz/api/reseller/v1', '/');
$path = '/domains/{domainUuid}/registrant-verification';
$path = str_replace('{domainUuid}', rawurlencode(requiredEnv('DOMAIN_UUID')), $path);
$url = $baseUrl . $path;
$headers = [
    'Authorization: Bearer ' . requiredEnv('RESELLER_API_TOKEN'),
    'Accept: application/json',
    'Idempotency-Key: ' . requiredEnv('IDEMPOTENCY_KEY'),
    'Content-Type: application/json',
];
$body = '{
  "type": "eds",
  "payload_snapshot": {
    "domain-name": "example.kz",
    "domain-creation-time": "2026-10-01T08:00:00.000Z",
    "registrant-name": "Ivan Petrov",
    "registrant-org": null,
    "registrant-residencedetails-country": "KZ",
    "registrant-residencedetails-externalidtype": "IIN",
    "registrant-residencedetails-externalidvalue": "000000000000"
  },
  "signable_payload": "[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\\n\\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\\n\\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\\n---------------------------------------------------------------------------\\n* Домендік атау: example.kz\\n* Құрылған күні: 2026-10-01T08:00:00.000Z\\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\\n* Ұйым: \\n* Ел: KZ\\n* Құжат түрі: IIN\\n* Құжат нөмірі: 000000000000\\n\\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\\n\\nKazNIC. Барлық құқықтар қорғалған.\\n\\n\\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\\n\\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\\nказахстанского сегмента Интернета.\\n\\nДАННЫЕ ОПЕРАЦИИ:\\n---------------------------------------------------------------------------\\n* Доменное имя: example.kz\\n* Дата создания: 2026-10-01T08:00:00.000Z\\n* Регистрант (ФИО): Ivan Petrov\\n* Организация: \\n* Страна: KZ\\n* Тип документа: IIN\\n* Номер документа: 000000000000\\n\\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\\n\\nKazNIC. Все права защищены.",
  "signature": "REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER",
  "certificate": null,
  "eds_provider": "ncalayer",
  "signature_options": {
    "method": "kz.gov.pki.knca.basics.sign",
    "format": "cms",
    "decode": false,
    "encapsulate": false,
    "digested": false,
    "timestamp_applied": true,
    "cms_type": "CMS Detached",
    "cades_profile": "CAdES-T"
  }
}';
$responseHeaders = [];
$handle = curl_init($url);
if ($handle === false) {
    throw new RuntimeException('Cannot initialize cURL.');
}
try {
    if (!curl_setopt_array($handle, [
        CURLOPT_CUSTOMREQUEST => 'POST',
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => false,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT => 20,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_POSTFIELDS => $body,
        CURLOPT_HEADERFUNCTION => static function (CurlHandle $curl, string $line) use (&$responseHeaders): int {
            if (str_starts_with($line, 'HTTP/')) {
                $responseHeaders = [];
            } elseif (str_contains($line, ':')) {
                [$name, $value] = explode(':', $line, 2);
                $responseHeaders[strtolower(trim($name))] = trim($value);
            }
            return strlen($line);
        },
    ])) {
        throw new RuntimeException('Cannot configure cURL.');
    }
    $raw = curl_exec($handle);
    if ($raw === false) {
        throw new RuntimeException('Transport failure; result may be unknown. cURL code: ' . curl_errno($handle));
    }
    $status = (int) curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
} finally {
    unset($handle);
}
$requestId = $responseHeaders['x-request-id'] ?? null;
$retryAfter = $responseHeaders['retry-after'] ?? null;
$data = null;
if ($raw !== '' && !in_array($status, [204, 205], true)) {
    try {
        $data = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
    } catch (JsonException $error) {
        if ($status >= 200 && $status < 300) {
            throw new RuntimeException('Unexpected non-JSON success response.', 0, $error);
        }
    }
}
if ($status < 200 || $status >= 300) {
    // Inspect $data['error']; queue 429 using $retryAfter, never create a new write key blindly.
    throw new RuntimeException('HTTP ' . $status . '; request_id=' . ($requestId ?? '-') . '; retry_after=' . ($retryAfter ?? '-'));
}
// $data contains the decoded response; 202 means accepted, not completed.
echo 'HTTP ' . $status . PHP_EOL;
js
// Node.js 22+; save as request.mjs. No third-party dependencies.
function requiredEnv(name) {
  const value = process.env[name];
  if (!value || /[\r\n]/u.test(value)) throw new Error('Set a valid environment variable: ' + name);
  return value;
}
const baseUrl = (process.env.API_BASE_URL || "https://api.b.websoft.kz/api/reseller/v1").replace(/\/$/u, '');
let path = "/domains/{domainUuid}/registrant-verification";
path = path.replaceAll("{domainUuid}", encodeURIComponent(requiredEnv("DOMAIN_UUID")));
const url = baseUrl + path;
const body = `{
  "type": "eds",
  "payload_snapshot": {
    "domain-name": "example.kz",
    "domain-creation-time": "2026-10-01T08:00:00.000Z",
    "registrant-name": "Ivan Petrov",
    "registrant-org": null,
    "registrant-residencedetails-country": "KZ",
    "registrant-residencedetails-externalidtype": "IIN",
    "registrant-residencedetails-externalidvalue": "000000000000"
  },
  "signable_payload": "[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\\n\\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\\n\\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\\n---------------------------------------------------------------------------\\n* Домендік атау: example.kz\\n* Құрылған күні: 2026-10-01T08:00:00.000Z\\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\\n* Ұйым: \\n* Ел: KZ\\n* Құжат түрі: IIN\\n* Құжат нөмірі: 000000000000\\n\\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\\n\\nKazNIC. Барлық құқықтар қорғалған.\\n\\n\\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\\n\\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\\nказахстанского сегмента Интернета.\\n\\nДАННЫЕ ОПЕРАЦИИ:\\n---------------------------------------------------------------------------\\n* Доменное имя: example.kz\\n* Дата создания: 2026-10-01T08:00:00.000Z\\n* Регистрант (ФИО): Ivan Petrov\\n* Организация: \\n* Страна: KZ\\n* Тип документа: IIN\\n* Номер документа: 000000000000\\n\\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\\n\\nKazNIC. Все права защищены.",
  "signature": "REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER",
  "certificate": null,
  "eds_provider": "ncalayer",
  "signature_options": {
    "method": "kz.gov.pki.knca.basics.sign",
    "format": "cms",
    "decode": false,
    "encapsulate": false,
    "digested": false,
    "timestamp_applied": true,
    "cms_type": "CMS Detached",
    "cades_profile": "CAdES-T"
  }
}`;
const response = await fetch(url, {
  method: "POST",
  redirect: 'manual',
  signal: AbortSignal.timeout(20_000),
  headers: {
    Authorization: 'Bearer ' + requiredEnv('RESELLER_API_TOKEN'),
    Accept: 'application/json',
    'Idempotency-Key': requiredEnv('IDEMPOTENCY_KEY'),
    "Content-Type": "application/json",
  },
  body,
});
const requestId = response.headers.get('x-request-id');
const retryAfter = response.headers.get('retry-after');
const raw = await response.text();
let data = null;
if (raw && ![204, 205].includes(response.status)) {
  try { data = JSON.parse(raw); }
  catch (cause) { if (response.ok) throw new Error('Unexpected non-JSON success response.', { cause }); }
}
if (!response.ok) {
  // Inspect data?.error; schedule 429 using retryAfter. Do not generate another write key.
  throw new Error('HTTP ' + response.status + '; request_id=' + requestId + '; retry_after=' + retryAfter);
}
// A timeout may have an unknown result. No automatic mutation retry in this example.
// data contains the response; 202 means accepted, not completed.
console.log('HTTP', response.status);
python
# Python 3.10+; standard library only.
import json
import os
from urllib.error import HTTPError
from urllib.parse import quote
from urllib.request import HTTPRedirectHandler, Request, build_opener

def required_env(name):
    value = os.environ.get(name, "")
    if not value or "\r" in value or "\n" in value:
        raise RuntimeError("Set a valid environment variable: " + name)
    return value

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

base_url = os.environ.get("API_BASE_URL", "https://api.b.websoft.kz/api/reseller/v1").rstrip("/")
path = "/domains/{domainUuid}/registrant-verification"
path = path.replace("{domainUuid}", quote(required_env("DOMAIN_UUID"), safe=""))
url = base_url + path
headers = {
    "Authorization": "Bearer " + required_env("RESELLER_API_TOKEN"),
    "Accept": "application/json",
    "Idempotency-Key": required_env("IDEMPOTENCY_KEY"),
    "Content-Type": "application/json",
}
body = "{\n  \"type\": \"eds\",\n  \"payload_snapshot\": {\n    \"domain-name\": \"example.kz\",\n    \"domain-creation-time\": \"2026-10-01T08:00:00.000Z\",\n    \"registrant-name\": \"Ivan Petrov\",\n    \"registrant-org\": null,\n    \"registrant-residencedetails-country\": \"KZ\",\n    \"registrant-residencedetails-externalidtype\": \"IIN\",\n    \"registrant-residencedetails-externalidvalue\": \"000000000000\"\n  },\n  \"signable_payload\": \"[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\\n\\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\\n\\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\\n---------------------------------------------------------------------------\\n* Домендік атау: example.kz\\n* Құрылған күні: 2026-10-01T08:00:00.000Z\\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\\n* Ұйым: \\n* Ел: KZ\\n* Құжат түрі: IIN\\n* Құжат нөмірі: 000000000000\\n\\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\\n\\nKazNIC. Барлық құқықтар қорғалған.\\n\\n\\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\\n\\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\\nказахстанского сегмента Интернета.\\n\\nДАННЫЕ ОПЕРАЦИИ:\\n---------------------------------------------------------------------------\\n* Доменное имя: example.kz\\n* Дата создания: 2026-10-01T08:00:00.000Z\\n* Регистрант (ФИО): Ivan Petrov\\n* Организация: \\n* Страна: KZ\\n* Тип документа: IIN\\n* Номер документа: 000000000000\\n\\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\\n\\nKazNIC. Все права защищены.\",\n  \"signature\": \"REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER\",\n  \"certificate\": null,\n  \"eds_provider\": \"ncalayer\",\n  \"signature_options\": {\n    \"method\": \"kz.gov.pki.knca.basics.sign\",\n    \"format\": \"cms\",\n    \"decode\": false,\n    \"encapsulate\": false,\n    \"digested\": false,\n    \"timestamp_applied\": true,\n    \"cms_type\": \"CMS Detached\",\n    \"cades_profile\": \"CAdES-T\"\n  }\n}".encode("utf-8")
request = Request(url, data=body, headers=headers, method="POST")
opener = build_opener(NoRedirect())
try:
    response = opener.open(request, timeout=20)
except HTTPError as error:
    response = error  # HTTP failure still has a response body and headers.
# Network/timeout exceptions propagate: a write may already have been accepted.
with response:
    status = response.status
    request_id = response.headers.get("X-Request-ID")
    retry_after = response.headers.get("Retry-After")
    raw = response.read()
data = None
if raw and status not in (204, 205):
    try:
        data = json.loads(raw)
    except (ValueError, UnicodeDecodeError):
        if 200 <= status < 300:
            raise RuntimeError("Unexpected non-JSON success response.")
if not 200 <= status < 300:
    # Inspect data['error']; schedule 429 with retry_after, keeping the same persisted key.
    raise RuntimeError(f"HTTP {status}; request_id={request_id}; retry_after={retry_after}")
# data contains the response. Do not log secrets/PII; 202 is not completion.
print("HTTP", status)
go
// Go 1.22+; standard library only. Save as main.go and run: go run main.go
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strings"
    "time"
)

func requiredEnv(name string) string {
    value := os.Getenv(name)
    if value == "" || strings.ContainsAny(value, "\r\n") { panic("Set a valid environment variable: " + name) }
    return value
}

func main() {
    baseURL := os.Getenv("API_BASE_URL")
    if baseURL == "" { baseURL = "https://api.b.websoft.kz/api/reseller/v1" }
    path := "/domains/{domainUuid}/registrant-verification"
    value0 := requiredEnv("DOMAIN_UUID")
    path = strings.ReplaceAll(path, "{domainUuid}", url.PathEscape(value0))
    endpoint := strings.TrimRight(baseURL, "/") + path
    request, err := http.NewRequest("POST", endpoint, strings.NewReader("{\n  \"type\": \"eds\",\n  \"payload_snapshot\": {\n    \"domain-name\": \"example.kz\",\n    \"domain-creation-time\": \"2026-10-01T08:00:00.000Z\",\n    \"registrant-name\": \"Ivan Petrov\",\n    \"registrant-org\": null,\n    \"registrant-residencedetails-country\": \"KZ\",\n    \"registrant-residencedetails-externalidtype\": \"IIN\",\n    \"registrant-residencedetails-externalidvalue\": \"000000000000\"\n  },\n  \"signable_payload\": \"[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\\n\\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\\n\\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\\n---------------------------------------------------------------------------\\n* Домендік атау: example.kz\\n* Құрылған күні: 2026-10-01T08:00:00.000Z\\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\\n* Ұйым: \\n* Ел: KZ\\n* Құжат түрі: IIN\\n* Құжат нөмірі: 000000000000\\n\\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\\n\\nKazNIC. Барлық құқықтар қорғалған.\\n\\n\\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\\n\\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\\nказахстанского сегмента Интернета.\\n\\nДАННЫЕ ОПЕРАЦИИ:\\n---------------------------------------------------------------------------\\n* Доменное имя: example.kz\\n* Дата создания: 2026-10-01T08:00:00.000Z\\n* Регистрант (ФИО): Ivan Petrov\\n* Организация: \\n* Страна: KZ\\n* Тип документа: IIN\\n* Номер документа: 000000000000\\n\\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\\n\\nKazNIC. Все права защищены.\",\n  \"signature\": \"REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER\",\n  \"certificate\": null,\n  \"eds_provider\": \"ncalayer\",\n  \"signature_options\": {\n    \"method\": \"kz.gov.pki.knca.basics.sign\",\n    \"format\": \"cms\",\n    \"decode\": false,\n    \"encapsulate\": false,\n    \"digested\": false,\n    \"timestamp_applied\": true,\n    \"cms_type\": \"CMS Detached\",\n    \"cades_profile\": \"CAdES-T\"\n  }\n}"))
    if err != nil { panic(err) }
    request.Header.Set("Authorization", "Bearer " + requiredEnv("RESELLER_API_TOKEN"))
    request.Header.Set("Accept", "application/json")
    request.Header.Set("Idempotency-Key", requiredEnv("IDEMPOTENCY_KEY"))
    request.Header.Set("Content-Type", "application/json")
    client := &http.Client{
        Timeout: 20 * time.Second,
        CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },
    }
    response, err := client.Do(request)
    if err != nil { panic("Transport failure; operation result may be unknown") }
    defer response.Body.Close()
    raw, err := io.ReadAll(response.Body)
    if err != nil { panic("Response read failed; operation result may be unknown") }
    requestID := response.Header.Get("X-Request-ID")
    retryAfter := response.Header.Get("Retry-After")
    var data any
    if len(raw) > 0 && response.StatusCode != 204 && response.StatusCode != 205 {
        decoder := json.NewDecoder(strings.NewReader(string(raw)))
        decoder.UseNumber() // Preserve integer money/identifiers without float rounding.
        if err := decoder.Decode(&data); err != nil && response.StatusCode >= 200 && response.StatusCode < 300 { panic("Unexpected non-JSON success response") }
    }
    if response.StatusCode < 200 || response.StatusCode >= 300 {
        // Inspect data; schedule 429 using retryAfter. Never create a new key blindly.
        panic(fmt.Sprintf("HTTP %d; request_id=%s; retry_after=%s", response.StatusCode, requestID, retryAfter))
    }
    // data holds the JSON value; 202 means accepted, not completed. Do not log secrets.
    fmt.Println("HTTP", response.StatusCode)
}
java
// Java 17+; standard library only. Save as RequestExample.java.
// Run: java RequestExample.java
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

public class RequestExample {
    private static String requiredEnv(String name) {
        String value = System.getenv(name);
        if (value == null || value.isEmpty() || value.contains("\r") || value.contains("\n")) {
            throw new IllegalStateException("Set a valid environment variable: " + name);
        }
        return value;
    }
    private static String envOr(String name, String fallback) {
        String value = System.getenv(name);
        return value == null || value.isEmpty() ? fallback : value;
    }
    public static void main(String[] args) throws Exception {
        String baseUrl = envOr("API_BASE_URL", "https://api.b.websoft.kz/api/reseller/v1").replaceAll("/+$", "");
        String path = "/domains/{domainUuid}/registrant-verification";
        path = path.replace("{domainUuid}", URLEncoder.encode(requiredEnv("DOMAIN_UUID"), StandardCharsets.UTF_8).replace("+", "%20"));
        URI uri = URI.create(baseUrl + path);
        String body = "{\n  \"type\": \"eds\",\n  \"payload_snapshot\": {\n    \"domain-name\": \"example.kz\",\n    \"domain-creation-time\": \"2026-10-01T08:00:00.000Z\",\n    \"registrant-name\": \"Ivan Petrov\",\n    \"registrant-org\": null,\n    \"registrant-residencedetails-country\": \"KZ\",\n    \"registrant-residencedetails-externalidtype\": \"IIN\",\n    \"registrant-residencedetails-externalidvalue\": \"000000000000\"\n  },\n  \"signable_payload\": \"[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\\n\\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\\n\\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\\n---------------------------------------------------------------------------\\n* Домендік атау: example.kz\\n* Құрылған күні: 2026-10-01T08:00:00.000Z\\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\\n* Ұйым: \\n* Ел: KZ\\n* Құжат түрі: IIN\\n* Құжат нөмірі: 000000000000\\n\\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\\n\\nKazNIC. Барлық құқықтар қорғалған.\\n\\n\\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\\n\\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\\nказахстанского сегмента Интернета.\\n\\nДАННЫЕ ОПЕРАЦИИ:\\n---------------------------------------------------------------------------\\n* Доменное имя: example.kz\\n* Дата создания: 2026-10-01T08:00:00.000Z\\n* Регистрант (ФИО): Ivan Petrov\\n* Организация: \\n* Страна: KZ\\n* Тип документа: IIN\\n* Номер документа: 000000000000\\n\\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\\n\\nKazNIC. Все права защищены.\",\n  \"signature\": \"REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER\",\n  \"certificate\": null,\n  \"eds_provider\": \"ncalayer\",\n  \"signature_options\": {\n    \"method\": \"kz.gov.pki.knca.basics.sign\",\n    \"format\": \"cms\",\n    \"decode\": false,\n    \"encapsulate\": false,\n    \"digested\": false,\n    \"timestamp_applied\": true,\n    \"cms_type\": \"CMS Detached\",\n    \"cades_profile\": \"CAdES-T\"\n  }\n}";
        HttpRequest request = HttpRequest.newBuilder(uri)
            .timeout(Duration.ofSeconds(20))
            .header("Authorization", "Bearer " + requiredEnv("RESELLER_API_TOKEN"))
            .header("Accept", "application/json")
            .header("Idempotency-Key", requiredEnv("IDEMPOTENCY_KEY"))
            .header("Content-Type", "application/json")
            .method("POST", HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
            .build();
        HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(5))
            .followRedirects(HttpClient.Redirect.NEVER)
            .build();
        // Reuse HttpClient in production. A timeout may mean an unknown write result.
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
        int status = response.statusCode();
        String requestId = response.headers().firstValue("X-Request-ID").orElse("");
        String retryAfter = response.headers().firstValue("Retry-After").orElse("");
        String responseBody = (status == 204 || status == 205) ? "" : response.body();
        if (status < 200 || status >= 300) {
            // Decode responseBody with your JSON library; schedule 429 using retryAfter.
            throw new IllegalStateException("HTTP " + status + "; request_id=" + requestId + "; retry_after=" + retryAfter);
        }
        // Java SE has no JSON object mapper: pass responseBody to your project's JSON parser.
        // Do not parse an empty 204 body; 202 means accepted, not completed.
        System.out.println("HTTP " + status);
    }
}
csharp
// C# / .NET 8+ console app; standard library only. Save as Program.cs.
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;

static string RequiredEnv(string name)
{
    string? value = Environment.GetEnvironmentVariable(name);
    if (string.IsNullOrEmpty(value) || value.Contains('\r') || value.Contains('\n'))
        throw new InvalidOperationException("Set a valid environment variable: " + name);
    return value;
}

string baseUrl = (Environment.GetEnvironmentVariable("API_BASE_URL") ?? "https://api.b.websoft.kz/api/reseller/v1").TrimEnd('/');
string path = "/domains/{domainUuid}/registrant-verification";
path = path.Replace("{domainUuid}", Uri.EscapeDataString(RequiredEnv("DOMAIN_UUID")));
using var handler = new HttpClientHandler { AllowAutoRedirect = false };
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(20) };
// Reuse HttpClient (or IHttpClientFactory) in production, not one client per request.
using var request = new HttpRequestMessage(new HttpMethod("POST"), baseUrl + path);
request.Headers.Add("Authorization", "Bearer " + RequiredEnv("RESELLER_API_TOKEN"));
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Idempotency-Key", RequiredEnv("IDEMPOTENCY_KEY"));
request.Content = new StringContent("{\n  \"type\": \"eds\",\n  \"payload_snapshot\": {\n    \"domain-name\": \"example.kz\",\n    \"domain-creation-time\": \"2026-10-01T08:00:00.000Z\",\n    \"registrant-name\": \"Ivan Petrov\",\n    \"registrant-org\": null,\n    \"registrant-residencedetails-country\": \"KZ\",\n    \"registrant-residencedetails-externalidtype\": \"IIN\",\n    \"registrant-residencedetails-externalidvalue\": \"000000000000\"\n  },\n  \"signable_payload\": \"[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\\n\\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\\n\\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\\n---------------------------------------------------------------------------\\n* Домендік атау: example.kz\\n* Құрылған күні: 2026-10-01T08:00:00.000Z\\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\\n* Ұйым: \\n* Ел: KZ\\n* Құжат түрі: IIN\\n* Құжат нөмірі: 000000000000\\n\\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\\n\\nKazNIC. Барлық құқықтар қорғалған.\\n\\n\\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\\n\\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\\nказахстанского сегмента Интернета.\\n\\nДАННЫЕ ОПЕРАЦИИ:\\n---------------------------------------------------------------------------\\n* Доменное имя: example.kz\\n* Дата создания: 2026-10-01T08:00:00.000Z\\n* Регистрант (ФИО): Ivan Petrov\\n* Организация: \\n* Страна: KZ\\n* Тип документа: IIN\\n* Номер документа: 000000000000\\n\\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\\n\\nKazNIC. Все права защищены.\",\n  \"signature\": \"REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER\",\n  \"certificate\": null,\n  \"eds_provider\": \"ncalayer\",\n  \"signature_options\": {\n    \"method\": \"kz.gov.pki.knca.basics.sign\",\n    \"format\": \"cms\",\n    \"decode\": false,\n    \"encapsulate\": false,\n    \"digested\": false,\n    \"timestamp_applied\": true,\n    \"cms_type\": \"CMS Detached\",\n    \"cades_profile\": \"CAdES-T\"\n  }\n}", Encoding.UTF8, "application/json");

// Transport exceptions may have an unknown result; do not issue a new mutation automatically.
using var response = await client.SendAsync(request);
int status = (int)response.StatusCode;
string requestId = response.Headers.TryGetValues("X-Request-ID", out var ids) ? string.Join(",", ids) : "";
string retryAfter = response.Headers.TryGetValues("Retry-After", out var delays) ? string.Join(",", delays) : "";
string raw = await response.Content.ReadAsStringAsync();
JsonElement? data = null;
if (raw.Length > 0 && status != 204 && status != 205)
{
    try { using var document = JsonDocument.Parse(raw); data = document.RootElement.Clone(); }
    catch (JsonException) { if (response.IsSuccessStatusCode) throw; }
}
if (!response.IsSuccessStatusCode)
{
    // Inspect data; schedule 429 using retryAfter and preserve the same key/body.
    throw new HttpRequestException($"HTTP {status}; request_id={requestId}; retry_after={retryAfter}");
}
// data contains JSON, or null for 204. HTTP 202 is not completion.
Console.WriteLine($"HTTP {status}");

Ответы ​

Условия ошибок и восстановление ​

HTTPКодКогда возникаетЧто делать
401unauthenticatedНет действительного Bearer API-ключа.Проверьте ключ, срок действия и окружение; не повторяйте бесконечно.
403forbiddenНет требуемого scope, провайдер/ключ/доступ запрещён.Проверьте настройки провайдера и scopes ключа.
429rate_limit_exceededИсчерпан общий лимит ключа.Выждите Retry-After; повторы выполняйте с backoff и jitter.
500internal_errorНеобработанный сбой инфраструктуры или внешнего драйвера.Сохраните request_id. Для изменения сначала проверьте существующую задачу; не генерируйте новый ключ вслепую. Формат ответа reverse proxy может отличаться от API.
404resource_not_foundUUID не найден у этого провайдера/окружения, либо запись удалена/скрыта migration hold.Проверьте UUID, test/live и принадлежность. Не пытайтесь получить ресурс чужого провайдера.
409conflictИнтеграция неактивна или migration hold.Обратитесь к оператору.
422validation_failedНе хватает полей; type=eds без signature/options; уже pending/verified или конкурентная обработка.Исправьте формат либо дождитесь текущей попытки. Новый Idempotency-Key не снимает блокировку pending.
409conflictКлюч уже используется другим запросом или исходный запрос ещё выполняется.Не изменяйте тело при повторе. Проверьте исходную операцию; используйте новый ключ только для нового намеренного действия.
422validation_failedНевалидный JSON-пayload/поле или отсутствует Idempotency-Key.Исправьте данные по error.details; для изменённого запроса создайте новый ключ.
404resource_not_foundReseller API глобально выключен конфигурацией.Уточните base URL и включение API у оператора.

HTTP 201 ​

Запись создана; проверяйте прикладной status.

Заголовок Idempotency-Replayed: Присутствует со значением true при возврате сохранённого HTTP-ответа.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаconst: "true"

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["data"]Схема: DomainVerificationEnvelope
$.dataobjectДаrequired: ["uuid","type","status","eds_provider","verification_status","verified_at","failed_at","expires_at","failure_message"]
$.data.uuidstringДаformat: "uuid"UUID попытки проверки.
$.data.typestringДаСпособ проверки, например eds.
$.data.statusstringДаСостояние попытки; как минимум pending, verified, failed. HTTP 201 не означает verified.
$.data.eds_providerstring / nullДаПровайдер подписи.
$.data.verification_statusstringДаДублирует status этой попытки.
$.data.verified_atstring / nullДаformat: "date-time"Время успешной проверки или null.
$.data.failed_atstring / nullДаformat: "date-time"Время отказа или null.
$.data.expires_atstring / nullДаformat: "date-time"Срок действия подтверждения либо null; не путать со сроком домена/документа.
$.data.failure_messagestring / nullДаЛокализованная причина отказа; отдельный failure_code в этом ресурсе не выдаётся.

Подпись принята, ожидается реестр (201) ​

json
{
  "data": {
    "uuid": "019a1234-1000-7000-8000-000000000010",
    "type": "eds",
    "status": "pending",
    "eds_provider": "ncalayer",
    "verification_status": "pending",
    "verified_at": null,
    "failed_at": null,
    "expires_at": null,
    "failure_message": null
  }
}

Владелец подтверждён (201) ​

json
{
  "data": {
    "uuid": "019a1234-1000-7000-8000-000000000010",
    "type": "eds",
    "status": "verified",
    "eds_provider": "ncalayer",
    "verification_status": "verified",
    "verified_at": "2026-10-05T08:00:05+00:00",
    "failed_at": null,
    "expires_at": null,
    "failure_message": null
  }
}

HTTP 201: попытка создана, но подпись отклонена (201) ​

json
{
  "data": {
    "uuid": "019a1234-1000-7000-8000-000000000010",
    "type": "eds",
    "status": "failed",
    "eds_provider": "ncalayer",
    "verification_status": "failed",
    "verified_at": null,
    "failed_at": "2026-10-05T08:00:05+00:00",
    "expires_at": null,
    "failure_message": "Подписанный документ не совпадает с актуальными данными владельца."
  }
}

HTTP 401 ​

Отсутствует, неверен, отозван или просрочен Bearer-ключ.

Заголовок X-Request-ID: UUID текущего запроса. Корректный входной X-Request-ID принимается в нижнем регистре, иначе создаётся новый. Не гарантирован для proxy/неизвестного маршрута.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["error"]Собственный JSON-конверт API, не RFC 9457. Структура и code не зависят от языка; message и details предназначены человеку. До выбора маршрута и на proxy этот конверт не гарантирован. Схема: ErrorEnvelope
$.errorobjectДаrequired: ["code","message","details","request_id"]
$.error.codestringДаМашинный код; не извлекайте причину из message.
$.error.messagestringДаЧеловекочитаемое, частично локализуемое сообщение; не стабильный идентификатор ошибки.
$.error.detailsoneOfДаБез подробностей возвращается [], не null и не {}. Валидация: {поле:[сообщения]}. Квота: {retry_after:секунды}.
$.error.details (oneOf 1)arrayДаmaxItems: 0
$.error.details (oneOf 2)objectДа
$.error.details (oneOf 2).*arrayНет
$.error.details (oneOf 2).*[]stringДа
$.error.details (oneOf 3)objectДаrequired: ["retry_after"]; Дополнительные поля запрещены
$.error.details (oneOf 3).retry_afterintegerДаminimum: 0
$.error.request_idstring / nullДаformat: "uuid"UUID для диагностики или null без контекста. При HTTP replay тело может содержать исходный ID, заголовок X-Request-ID относится к текущей попытке.

default (401) ​

json
{
  "error": {
    "code": "unauthenticated",
    "message": "API credential is missing or invalid.",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

HTTP 403 ​

Нет scope, IP не разрешён, тариф/режим/статус реселлера запрещает действие либо test-ключ обращается к live-only ресурсу.

Заголовок X-Request-ID: UUID текущего запроса. Корректный входной X-Request-ID принимается в нижнем регистре, иначе создаётся новый. Не гарантирован для proxy/неизвестного маршрута.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["error"]Собственный JSON-конверт API, не RFC 9457. Структура и code не зависят от языка; message и details предназначены человеку. До выбора маршрута и на proxy этот конверт не гарантирован. Схема: ErrorEnvelope
$.errorobjectДаrequired: ["code","message","details","request_id"]
$.error.codestringДаМашинный код; не извлекайте причину из message.
$.error.messagestringДаЧеловекочитаемое, частично локализуемое сообщение; не стабильный идентификатор ошибки.
$.error.detailsoneOfДаБез подробностей возвращается [], не null и не {}. Валидация: {поле:[сообщения]}. Квота: {retry_after:секунды}.
$.error.details (oneOf 1)arrayДаmaxItems: 0
$.error.details (oneOf 2)objectДа
$.error.details (oneOf 2).*arrayНет
$.error.details (oneOf 2).*[]stringДа
$.error.details (oneOf 3)objectДаrequired: ["retry_after"]; Дополнительные поля запрещены
$.error.details (oneOf 3).retry_afterintegerДаminimum: 0
$.error.request_idstring / nullДаformat: "uuid"UUID для диагностики или null без контекста. При HTTP replay тело может содержать исходный ID, заголовок X-Request-ID относится к текущей попытке.

default (403) ​

json
{
  "error": {
    "code": "forbidden",
    "message": "Source IP address is not allowed.",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

supportTest (403) ​

json
{
  "error": {
    "code": "forbidden",
    "message": "Support is available only to live credentials.",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

HTTP 404 ​

Ресурс недоступен в контексте или весь reseller API отключён. Не отличайте чужое от отсутствующего.

Заголовок X-Request-ID: UUID текущего запроса. Корректный входной X-Request-ID принимается в нижнем регистре, иначе создаётся новый. Не гарантирован для proxy/неизвестного маршрута.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["error"]Собственный JSON-конверт API, не RFC 9457. Структура и code не зависят от языка; message и details предназначены человеку. До выбора маршрута и на proxy этот конверт не гарантирован. Схема: ErrorEnvelope
$.errorobjectДаrequired: ["code","message","details","request_id"]
$.error.codestringДаМашинный код; не извлекайте причину из message.
$.error.messagestringДаЧеловекочитаемое, частично локализуемое сообщение; не стабильный идентификатор ошибки.
$.error.detailsoneOfДаБез подробностей возвращается [], не null и не {}. Валидация: {поле:[сообщения]}. Квота: {retry_after:секунды}.
$.error.details (oneOf 1)arrayДаmaxItems: 0
$.error.details (oneOf 2)objectДа
$.error.details (oneOf 2).*arrayНет
$.error.details (oneOf 2).*[]stringДа
$.error.details (oneOf 3)objectДаrequired: ["retry_after"]; Дополнительные поля запрещены
$.error.details (oneOf 3).retry_afterintegerДаminimum: 0
$.error.request_idstring / nullДаformat: "uuid"UUID для диагностики или null без контекста. При HTTP replay тело может содержать исходный ID, заголовок X-Request-ID относится к текущей попытке.

default (404) ​

json
{
  "error": {
    "code": "resource_not_found",
    "message": "Not Found",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

HTTP 409 ​

Конфликт ключа идемпотентности или состояния. Устраните причину.

Заголовок X-Request-ID: UUID текущего запроса. Корректный входной X-Request-ID принимается в нижнем регистре, иначе создаётся новый. Не гарантирован для proxy/неизвестного маршрута.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["error"]Собственный JSON-конверт API, не RFC 9457. Структура и code не зависят от языка; message и details предназначены человеку. До выбора маршрута и на proxy этот конверт не гарантирован. Схема: ErrorEnvelope
$.errorobjectДаrequired: ["code","message","details","request_id"]
$.error.codestringДаМашинный код; не извлекайте причину из message.
$.error.messagestringДаЧеловекочитаемое, частично локализуемое сообщение; не стабильный идентификатор ошибки.
$.error.detailsoneOfДаБез подробностей возвращается [], не null и не {}. Валидация: {поле:[сообщения]}. Квота: {retry_after:секунды}.
$.error.details (oneOf 1)arrayДаmaxItems: 0
$.error.details (oneOf 2)objectДа
$.error.details (oneOf 2).*arrayНет
$.error.details (oneOf 2).*[]stringДа
$.error.details (oneOf 3)objectДаrequired: ["retry_after"]; Дополнительные поля запрещены
$.error.details (oneOf 3).retry_afterintegerДаminimum: 0
$.error.request_idstring / nullДаformat: "uuid"UUID для диагностики или null без контекста. При HTTP replay тело может содержать исходный ID, заголовок X-Request-ID относится к текущей попытке.

default (409) ​

json
{
  "error": {
    "code": "conflict",
    "message": "A request with this Idempotency-Key is already processing.",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

changedRequest (409) ​

json
{
  "error": {
    "code": "conflict",
    "message": "Idempotency-Key was already used with a different request.",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

HTTP 422 ​

Ошибка данных или обязательного заголовка. details может быть [].

Заголовок X-Request-ID: UUID текущего запроса. Корректный входной X-Request-ID принимается в нижнем регистре, иначе создаётся новый. Не гарантирован для proxy/неизвестного маршрута.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["error"]Собственный JSON-конверт API, не RFC 9457. Структура и code не зависят от языка; message и details предназначены человеку. До выбора маршрута и на proxy этот конверт не гарантирован. Схема: ErrorEnvelope
$.errorobjectДаrequired: ["code","message","details","request_id"]
$.error.codestringДаМашинный код; не извлекайте причину из message.
$.error.messagestringДаЧеловекочитаемое, частично локализуемое сообщение; не стабильный идентификатор ошибки.
$.error.detailsoneOfДаБез подробностей возвращается [], не null и не {}. Валидация: {поле:[сообщения]}. Квота: {retry_after:секунды}.
$.error.details (oneOf 1)arrayДаmaxItems: 0
$.error.details (oneOf 2)objectДа
$.error.details (oneOf 2).*arrayНет
$.error.details (oneOf 2).*[]stringДа
$.error.details (oneOf 3)objectДаrequired: ["retry_after"]; Дополнительные поля запрещены
$.error.details (oneOf 3).retry_afterintegerДаminimum: 0
$.error.request_idstring / nullДаformat: "uuid"UUID для диагностики или null без контекста. При HTTP replay тело может содержать исходный ID, заголовок X-Request-ID относится к текущей попытке.

default (422) ​

json
{
  "error": {
    "code": "validation_failed",
    "message": "A valid Idempotency-Key header is required.",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

fields (422) ​

json
{
  "error": {
    "code": "validation_failed",
    "message": "The name field is required.",
    "details": {
      "name": [
        "The name field is required."
      ]
    },
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

HTTP 429 ​

Квота API-ключа исчерпана. Ждите Retry-After. Собственный 429 не содержит X-RateLimit-Limit/Remaining/Reset.

Заголовок X-Request-ID: UUID текущего запроса. Корректный входной X-Request-ID принимается в нижнем регистре, иначе создаётся новый. Не гарантирован для proxy/неизвестного маршрута.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Заголовок Retry-After: На 429 API: целые секунды до сброса окна, не дата/Unix timestamp. При 0 добавьте jitter. Proxy может вернуть HTTP-date.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаpattern: "^[0-9]+$"
text
Retry-After: 42

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["error"]Собственный JSON-конверт API, не RFC 9457. Структура и code не зависят от языка; message и details предназначены человеку. До выбора маршрута и на proxy этот конверт не гарантирован. Схема: ErrorEnvelope
$.errorobjectДаrequired: ["code","message","details","request_id"]
$.error.codestringДаМашинный код; не извлекайте причину из message.
$.error.messagestringДаЧеловекочитаемое, частично локализуемое сообщение; не стабильный идентификатор ошибки.
$.error.detailsoneOfДаБез подробностей возвращается [], не null и не {}. Валидация: {поле:[сообщения]}. Квота: {retry_after:секунды}.
$.error.details (oneOf 1)arrayДаmaxItems: 0
$.error.details (oneOf 2)objectДа
$.error.details (oneOf 2).*arrayНет
$.error.details (oneOf 2).*[]stringДа
$.error.details (oneOf 3)objectДаrequired: ["retry_after"]; Дополнительные поля запрещены
$.error.details (oneOf 3).retry_afterintegerДаminimum: 0
$.error.request_idstring / nullДаformat: "uuid"UUID для диагностики или null без контекста. При HTTP replay тело может содержать исходный ID, заголовок X-Request-ID относится к текущей попытке.

default (429) ​

json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "API rate limit exceeded.",
    "details": {
      "retry_after": 42
    },
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

HTTP 500 ​

Этот HTTP-ответ не определяет результат записи. Сначала сверка; повтор только с прежним ключом и точным телом.

Заголовок X-Request-ID: UUID текущего запроса. Корректный входной X-Request-ID принимается в нижнем регистре, иначе создаётся новый. Не гарантирован для proxy/неизвестного маршрута.

ПолеТипОбязательно в родителеОграниченияОписание
$stringДаformat: "uuid"

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["error"]Собственный JSON-конверт API, не RFC 9457. Структура и code не зависят от языка; message и details предназначены человеку. До выбора маршрута и на proxy этот конверт не гарантирован. Схема: ErrorEnvelope
$.errorobjectДаrequired: ["code","message","details","request_id"]
$.error.codestringДаМашинный код; не извлекайте причину из message.
$.error.messagestringДаЧеловекочитаемое, частично локализуемое сообщение; не стабильный идентификатор ошибки.
$.error.detailsoneOfДаБез подробностей возвращается [], не null и не {}. Валидация: {поле:[сообщения]}. Квота: {retry_after:секунды}.
$.error.details (oneOf 1)arrayДаmaxItems: 0
$.error.details (oneOf 2)objectДа
$.error.details (oneOf 2).*arrayНет
$.error.details (oneOf 2).*[]stringДа
$.error.details (oneOf 3)objectДаrequired: ["retry_after"]; Дополнительные поля запрещены
$.error.details (oneOf 3).retry_afterintegerДаminimum: 0
$.error.request_idstring / nullДаformat: "uuid"UUID для диагностики или null без контекста. При HTTP replay тело может содержать исходный ID, заголовок X-Request-ID относится к текущей попытке.

default (500) ​

json
{
  "error": {
    "code": "internal_error",
    "message": "The request could not be completed.",
    "details": [],
    "request_id": "11111111-1111-4111-8111-111111111111"
  }
}

Дополнительные примеры из контракта ​

cURL ​

bash
BASE_URL='https://api.b.websoft.kz/api/reseller/v1'
# BASE_URL включает /api/reseller/v1. Подставьте реальные UUID своего окружения.
# Для нового намеренного действия задайте новый IDEMPOTENCY_KEY; для повтора сохраните прежний.
curl --request POST "$BASE_URL/domains/019a1234-1000-7000-8000-000000000001/registrant-verification" \
  --header "Authorization: Bearer $RESELLER_API_TOKEN" \
  --header "Accept: application/json" \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --header "Content-Type: application/json" \
  --data-raw '{
  "type": "eds",
  "payload_snapshot": {
    "domain-name": "example.kz",
    "domain-creation-time": "2026-10-01T08:00:00.000Z",
    "registrant-name": "Ivan Petrov",
    "registrant-org": null,
    "registrant-residencedetails-country": "KZ",
    "registrant-residencedetails-externalidtype": "IIN",
    "registrant-residencedetails-externalidvalue": "000000000000"
  },
  "signable_payload": "[KK] ТІРКЕУШІНІҢ ТІРКЕУ ДЕРЕКТЕРІН РАСТАУ ТУРАЛЫ ӨТІНІШ\n\nОсы өтініш арқылы мен көрсетілген домендік атаудың тіркеу деректерінің өзектілігі мен дұрыстығын Қазақстан интернет\nсегментіндегі домендік атауларды тіркеу, пайдалану және бөлу қағидаларына сәйкес толық растаймын.\n\nОПЕРАЦИЯ ТУРАЛЫ ДЕРЕКТЕР:\n---------------------------------------------------------------------------\n* Домендік атау: example.kz\n* Құрылған күні: 2026-10-01T08:00:00.000Z\n* Тіркеуші (Т.А.Ә.): Ivan Petrov\n* Ұйым: \n* Ел: KZ\n* Құжат түрі: IIN\n* Құжат нөмірі: 000000000000\n\nБұл құжат Қазақстандық торап ақпарат орталығына (KazNIC) жіберуге арналған.\n\nKazNIC. Барлық құқықтар қорғалған.\n\n\n[RU] ЗАЯВЛЕНИЕ НА ПОДТВЕРЖДЕНИЕ РЕГИСТРАЦИОННЫХ ДАННЫХ\n\nНастоящим действием я в полной мере подтверждаю актуальность и достоверность регистрационных данных указанного\nдоменного имени в соответствии с Правилами регистрации, пользования и распределения доменных имен в пространстве\nказахстанского сегмента Интернета.\n\nДАННЫЕ ОПЕРАЦИИ:\n---------------------------------------------------------------------------\n* Доменное имя: example.kz\n* Дата создания: 2026-10-01T08:00:00.000Z\n* Регистрант (ФИО): Ivan Petrov\n* Организация: \n* Страна: KZ\n* Тип документа: IIN\n* Номер документа: 000000000000\n\nДанный документ предназначен для отправки в Казахстанский центр сетевой информации (KazNIC).\n\nKazNIC. Все права защищены.",
  "signature": "REPLACE_WITH_BASE64_DER_CADES_T_FROM_NCALAYER",
  "certificate": null,
  "eds_provider": "ncalayer",
  "signature_options": {
    "method": "kz.gov.pki.knca.basics.sign",
    "format": "cms",
    "decode": false,
    "encapsulate": false,
    "digested": false,
    "timestamp_applied": true,
    "cms_type": "CMS Detached",
    "cades_profile": "CAdES-T"
  }
}'

Машиночитаемый контракт ​

OpenAPI JSON · OpenAPI YAML · Markdown этой операции

Источники проверки контракта
  • routes/api/reseller/v1.php
  • app/Application/ResellerApi/V1/Controller/DomainController.php