Skip to content

Исполняемые примеры ​

Примеры не зависят от Laravel и не содержат действующих ключей. У каждого запроса в справочнике, включая варианты тела, есть вкладки с примерами на семи языках. Все они генерируются из одних параметров OpenAPI и передают одинаковые метод, query, заголовки и JSON.

Языки запросов ​

ВкладкаТребования и HTTP-клиент
cURLCLI curl с поддержкой --fail-with-body
PHP 8+PHP 8.0 или новее, расширения curl и json; strict_types, типизированный CurlHandle, без Composer-зависимостей
JavaScript / Node.jsNode.js 22+, встроенный fetch; файл .mjs, не браузер
PythonPython 3.10+, стандартный urllib.request, без pip-зависимостей
GoGo 1.22+, стандартный net/http; файл main.go
JavaJava 17+, стандартный java.net.http.HttpClient; файл RequestExample.java
C# / .NET.NET 8+, консольный проект, стандартные HttpClient и System.Text.Json; файл Program.cs

Во всех серверных примерах настройте RESELLER_API_TOKEN, при необходимости API_BASE_URL, а для записи обязательный заранее сохранённый IDEMPOTENCY_KEY. UUID пути можно заменить прямо в примере либо задать переменной вроде DOMAIN_UUID. Демонстрационные UUID не являются действующими ресурсами. Не передавайте Bearer-ключ в браузер.

Примеры выполняют один вызов без собственного цикла повторов. Они ограничивают время запроса/ожидания, не следуют перенаправлениям с секретом, сохраняют X-Request-ID и Retry-After, различают HTTP-ошибку и сетевой сбой. 204 обрабатывается без JSON-декодирования. При 429, 5xx или timeout применяйте правила надёжности, а не запускайте новую покупку новым ключом.

В PHP, Node.js, Python, Go и C# декодированный ответ доступен в переменной data/$data. Java SE не включает объектный JSON-маппер: пример сохраняет responseBody, который следует передать JSON-библиотеке вашего проекта. Полные ответы с секретами и персональными данными намеренно не выводятся в консоль. Код 202 означает только приём операции, не её завершение.

В Java и C# для реального приложения переиспользуйте HTTP-клиент; показанный запуск является самостоятельным консольным примером. JSON и ключ сохраняйте до отправки, если реализуете восстановление после сбоя. Переключение языка не является способом повторить потерянный запрос: используйте исходные байты тела и ключ из своего журнала.

Официальная документация используемых клиентов: PHP cURL, Node.js fetch, Python urllib, Go net/http, Java HttpClient, .NET HttpClient.

Полноценный возобновляемый учебный сценарий ниже требует Node.js 22+. Он дополняет отдельные примеры запросов, а не заменяет их.

Файлы ​

  • transport.mjs: серверный HTTP-клиент, ограниченные повторы, Retry-After и чтение операций.
  • register.mjs: возобновляемый сценарий регистрации только в test.
  • registration-input.json: входные данные сценария.
  • transport.test.mjs: тесты сетевых отказов без обращения к API.
  • register.test.mjs: проверки сценария регистрации на локальном HTTP mock-сервере, без обращения к платформе или реестру.

Проверить примеры без внешнего API ​

В каталоге с файлами:

bash
node --test *.test.mjs

Транспортные тесты подменяют fetch и проверяют сохранение тела и ключа при сетевом сбое, ожидание 429, ограничение повторов 502, отказ от автоматического повторения 409/422, защиту URL и остановку при uncertain. Тесты runner запускают сценарий на локальном mock-сервере: managed с возобновлением сохранённого результата без повторных записей, aggregate без создания покупателя и без customer_uuid, превышение согласованной суммы, запрет live-ключа и запрет использования состояния другим credential. Это не тест доступности конкретного регистратора и не проверка валидации PHP-контроллеров.

Выполнить сценарий в sandbox ​

Сначала получите контекст, каталог и согласованные sandbox-данные. В registration-input.json замените zone_uuid на resource_uuid зоны из каталога, а также contact_uuid, имя домена и NS; установите собственные external_id и допустимую розничную сумму max_total_minor. Это локальные параметры примера, не отдельные поля тела API-запроса. Вместо существующего contact_uuid можно указать полный объект contact; в managed вместо создания клиента через customer можно задать существующий customer_uuid. В aggregate клиент назначается платформой, пример не отправляет customer_uuid ни в одном шаге.

bash
export RESELLER_API_BASE='https://api.b.websoft.kz/api/reseller/v1'
export RESELLER_API_TOKEN='rsl_test_REPLACE_KEY.REPLACE_SECRET'
node register.mjs registration-input.json /private/reseller-example/order-1001 --execute-test

Адрес API в опубликованном примере подставляется порталом из DOCS_API_URL; в исходнике используется шаблон, не готовый URL. Проверьте адрес перед передачей ключа. Скрипт отказывается от live-ключей и дополнительно проверяет окружение через /context. Флаг означает разрешение тестовых записей: sandbox всё равно может выполнять команды в тестовом реестре. Проверку доступности имени выполните заранее; она не гарантирует регистрацию.

Перед каждой отправкой сохраняются ключ, метод, путь и точное тело. После ответа сохраняется результат шага. Повтор запуска с тем же файлом, директорией и credential использует подтверждённые результаты без повторных записей. Если у сохранённого запроса нет ответа, автоматическое возобновление по умолчанию запрещено. Сначала согласуйте с оператором фактический TTL HTTP-idempotency: /context его не возвращает. Для допустимого повтора задайте RESELLER_REPLAY_WINDOW_SECONDS как целое положительное число секунд строго меньше серверного TTL, с запасом на время отправки и возможное расхождение часов. Возраст намерения отсчитывается от его первоначального сохранения. При неизвестном TTL или истёкшем окне сначала сверяйте UUID/external_id с оператором. Для другого заказа используется другая директория и другие external_id.

state.json содержит персональные данные и ответы, поэтому каталог должен находиться вне webroot, иметь ограниченные права и не попадать в Git или публичные backups. Встроенные права 0700/0600 применяются при создании; права уже существующей директории проверьте сами. Секрет ключа в state не сохраняется.

run.lock предотвращает параллельные запуски. После аварийного завершения сначала убедитесь, что старый процесс отсутствует, затем удалите только stale lock; не удаляйте state.json. Истёкший quote и изменение согласованной суммы требуют разбора, а не удаления состояния и повторной покупки.

Это учебный файловый журнал, не production-очередь: для реального биллинга используйте транзакционную БД, блокировки, защиту журналов и устойчивый scheduler. При остановке после отправки и до сохранения ответа HTTP-idempotency восстанавливает запрос лишь в пределах своего срока хранения; после длительного простоя сначала сверяйте external_id/UUID, не запускайте записи вслепую.

Использовать клиент в своей задаче ​

js
import { createClient, createIntent } from './transport.mjs';

const api = createClient({
  baseUrl: process.env.RESELLER_API_BASE,
  token: process.env.RESELLER_API_TOKEN,
});
const intent = createIntent('PUT', `/domains/${domainUuid}/nameservers`, {
  nameservers: [{ hostname: 'ns1.example.net' }, { hostname: 'ns2.example.net' }],
  reason: 'Согласованная смена DNS-провайдера',
});
// Сначала транзакционно сохранить intent в своей БД; при повторе загрузить его оттуда.
await intentStore.insert(intent);
const accepted = await api.request(intent);
await intentStore.attachOperation(intent.key, accepted.body.data.uuid);
const operation = await api.operation(accepted.body.data.uuid);
if (operation.status === 'completed') {
  const domain = await api.request(createIntent('GET', `/domains/${domainUuid}`));
  await domainStore.reconcile(domain.body.data);
} else {
  await intentStore.deferForReconciliation(intent.key, operation);
}

intentStore и domainStore обозначают ваш слой хранения, их нужно реализовать. Пример транспорта не координирует бюджет rate limit между несколькими процессами: общий ограничитель ключа добавляется в вашем scheduler. Длительный Retry-After возвращается как ошибка с задержкой для планировщика, а не сокращается до удобного значения.

Полная схема подписанного webhook и пример проверки HMAC приведены в разделе уведомлений. Не используйте этот исходящий API-клиент как проверку входящей подписи.