Skip to content

Получить точный документ для ЭЦП владельца ​

GET /domains/{domainUuid}/registrant-verification/payload

operationId: getRegistrantVerificationPayload

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

Домен должен быть создан в реестре; нужны активная интеграция и отсутствие migration hold. Если последняя принятая подпись pending или владелец уже verified, новая подготовка блокируется 422. Данные владельца могут запрашиваться у NIC.KZ. Подписывайте ТОЧНЫЕ UTF-8 байты signable_payload через NCALayer с возвращёнными параметрами; не собирайте документ самостоятельно и не подписывайте пример. payload_hash = SHA-256 текста. expires_at = issued_at+15 минут рекомендует обновить документ; submit не принимает отдельный подписанный token срока, а проверяет актуальный snapshot и точный текст. Ответ содержит идентификатор владельца, не сохраняйте его в публичных логах. Это не общая доменная Operation.

Лимит общий для всех запросов одного 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"

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

Тело запроса отсутствует.

Пример запроса ​

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}"

curl --request GET "$API_BASE_URL/domains/${DOMAIN_UUID}/registrant-verification/payload" \
  --connect-timeout 5 --max-time 20 --fail-with-body \
  --header "Authorization: Bearer $RESELLER_API_TOKEN" \
  --header 'Accept: application/json'
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/payload';
$path = str_replace('{domainUuid}', rawurlencode(requiredEnv('DOMAIN_UUID')), $path);
$url = $baseUrl . $path;
$headers = [
    'Authorization: Bearer ' . requiredEnv('RESELLER_API_TOKEN'),
    'Accept: application/json',

];

$responseHeaders = [];
$handle = curl_init($url);
if ($handle === false) {
    throw new RuntimeException('Cannot initialize cURL.');
}
try {
    if (!curl_setopt_array($handle, [
        CURLOPT_CUSTOMREQUEST => 'GET',
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => false,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT => 20,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        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/payload";
path = path.replaceAll("{domainUuid}", encodeURIComponent(requiredEnv("DOMAIN_UUID")));
const url = baseUrl + path;

const response = await fetch(url, {
  method: "GET",
  redirect: 'manual',
  signal: AbortSignal.timeout(20_000),
  headers: {
    Authorization: 'Bearer ' + requiredEnv('RESELLER_API_TOKEN'),
    Accept: 'application/json',

  },
});
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/payload"
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",

}
body = None
request = Request(url, data=body, headers=headers, method="GET")
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/payload"
    value0 := requiredEnv("DOMAIN_UUID")
    path = strings.ReplaceAll(path, "{domainUuid}", url.PathEscape(value0))
    endpoint := strings.TrimRight(baseURL, "/") + path
    request, err := http.NewRequest("GET", endpoint, nil)
    if err != nil { panic(err) }
    request.Header.Set("Authorization", "Bearer " + requiredEnv("RESELLER_API_TOKEN"))
    request.Header.Set("Accept", "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/payload";
        path = path.replace("{domainUuid}", URLEncoder.encode(requiredEnv("DOMAIN_UUID"), StandardCharsets.UTF_8).replace("+", "%20"));
        URI uri = URI.create(baseUrl + path);
        HttpRequest request = HttpRequest.newBuilder(uri)
            .timeout(Duration.ofSeconds(20))
            .header("Authorization", "Bearer " + requiredEnv("RESELLER_API_TOKEN"))
            .header("Accept", "application/json")
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .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/payload";
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("GET"), baseUrl + path);
request.Headers.Add("Authorization", "Bearer " + RequiredEnv("RESELLER_API_TOKEN"));
request.Headers.Add("Accept", "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Домен не создан в реестре, последняя проверка pending или уже verified.Дождитесь завершения регистрации/верификации; повторная подпись не нужна.
404resource_not_foundReseller API глобально выключен конфигурацией.Уточните base URL и включение API у оператора.

HTTP 200 ​

Успешное чтение или сохранение настройки.

Content-Type: application/json

ПолеТипОбязательно в родителеОграниченияОписание
$objectДаrequired: ["data"]Схема: DomainVerificationPayloadEnvelope
$.dataobjectДаrequired: ["type","eds_provider","doc_spec_alg","signer_role","payload_hash","signable_payload","payload_snapshot","issued_at","expires_at","ncalayer_options","signature_options"]
$.data.typestringДаconst: "eds"Поддерживаемый способ.
$.data.eds_providerstringДаconst: "ncalayer"Провайдер подписи.
$.data.doc_spec_algstringДаconst: "DOC-SPEC-REGISTRANT-IDENTITY-CONFIRMATION-V1"Версия подписываемого документа.
$.data.signer_rolestringДаconst: "CURRENT_REGISTRANT"Текущий владелец домена.
$.data.payload_hashstringДаpattern: "^[a-f0-9]{64}$"SHA-256 точной строки signable_payload.
$.data.signable_payloadstringДаПолный двуязычный документ. Подписывайте без изменения пробелов, переносов, кодировки UTF-8 и порядка строк.
$.data.payload_snapshotobjectДаrequired: ["domain-name","domain-creation-time","registrant-name","registrant-org","registrant-residencedetails-country","registrant-residencedetails-externalidtype","registrant-residencedetails-externalidvalue"]Схема: DomainVerificationSnapshot
$.data.payload_snapshot.domain-namestringДаТочное имя из реестра, Punycode.
$.data.payload_snapshot.domain-creation-timestring / nullДаДата создания в EPP, сохраняйте исходную строку.
$.data.payload_snapshot.registrant-namestring / nullДаИмя владельца из реестра/манифеста.
$.data.payload_snapshot.registrant-orgstring / nullДаОрганизация владельца либо null.
$.data.payload_snapshot.registrant-residencedetails-countrystring / nullДаСтрана резидентства.
$.data.payload_snapshot.registrant-residencedetails-externalidtypestring / nullДаТип документа, например IIN/BIN.
$.data.payload_snapshot.registrant-residencedetails-externalidvaluestring / nullДаЧувствительный идентификатор владельца; не логируйте.
$.data.issued_atstringДаformat: "date-time"Время формирования.
$.data.expires_atstringДаformat: "date-time"Рекомендуемое время обновления документа (issued_at + 15 минут). При submit сервер сверяет актуальные данные и точный текст, но отдельный timestamp/token срока не принимает.
$.data.ncalayer_optionsobjectДаrequired: ["environment","allowedStorages","locale","signerParams"]
$.data.ncalayer_options.environmentstringДаОкружение NCALayer, test или production.
$.data.ncalayer_options.allowedStoragesanyOfДаРазрешённые хранилища или null в production.
$.data.ncalayer_options.allowedStorages (anyOf 1)arrayДаВ test [PKCS12].
$.data.ncalayer_options.allowedStorages (anyOf 1)[]stringДаИдентификатор хранилища.
$.data.ncalayer_options.allowedStorages (anyOf 2)nullДа
$.data.ncalayer_options.localestringДаЛокаль NCALayer.
$.data.ncalayer_options.signerParamsobjectДаrequired: ["extKeyUsageOids","chain"]
$.data.ncalayer_options.signerParams.extKeyUsageOidsarrayДаОграничения назначения сертификата.
$.data.ncalayer_options.signerParams.extKeyUsageOids[]stringДаOID назначения ключа.
$.data.ncalayer_options.signerParams.chainanyOfДаЦепочка сертификатов или null.
$.data.ncalayer_options.signerParams.chain (anyOf 1)arrayДаТестовая цепочка.
$.data.ncalayer_options.signerParams.chain (anyOf 1)[]stringДаСертификат цепочки.
$.data.ncalayer_options.signerParams.chain (anyOf 2)nullДа
$.data.signature_optionsobjectДаrequired: ["method","format","decode","encapsulate","digested","timestamp_applied","cms_type","cades_profile"]Схема: DomainSignatureOptions
$.data.signature_options.methodstringДаmaxLength: 80Для действительной подписи строго kz.gov.pki.knca.basics.sign.
$.data.signature_options.formatstringДаmaxLength: 20Для действительной подписи строго cms.
$.data.signature_options.decodebooleanДаconst: falseПодписываются исходные текстовые байты, не Base64-декодированный документ.
$.data.signature_options.encapsulatebooleanДаconst: falseТолько detached CMS.
$.data.signature_options.digestedbooleanДаconst: falseНе передавать предварительный дайджест вместо документа.
$.data.signature_options.timestamp_appliedbooleanДаconst: trueНужна метка времени CAdES-T.
$.data.signature_options.cms_typestringДаmaxLength: 80Для действительной подписи строго CMS Detached.
$.data.signature_options.cades_profilestringДаmaxLength: 80Для действительной подписи строго CAdES-T.

Полный документ и SHA-256; данные демонстрационные, не подписывать этот пример (200) ​

json
{
  "data": {
    "type": "eds",
    "eds_provider": "ncalayer",
    "doc_spec_alg": "DOC-SPEC-REGISTRANT-IDENTITY-CONFIRMATION-V1",
    "signer_role": "CURRENT_REGISTRANT",
    "payload_hash": "4f7ec7ab0a228267838add37968eb6f14cce085679ece865136db71afe11fb51",
    "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. Все права защищены.",
    "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"
    },
    "issued_at": "2026-10-05T08:00:00+00:00",
    "expires_at": "2026-10-05T08:15:00+00:00",
    "ncalayer_options": {
      "environment": "production",
      "allowedStorages": null,
      "locale": "ru",
      "signerParams": {
        "extKeyUsageOids": [
          "1.3.6.1.5.5.7.3.4"
        ],
        "chain": null
      }
    },
    "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"
    }
  }
}

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 GET "$BASE_URL/domains/019a1234-1000-7000-8000-000000000001/registrant-verification/payload" \
  --header "Authorization: Bearer $RESELLER_API_TOKEN" \
  --header "Accept: application/json"

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

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

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