Тема
Исполняемые примеры
Примеры не зависят от Laravel и не содержат действующих ключей. У каждого запроса в справочнике, включая варианты тела, есть вкладки с примерами на семи языках. Все они генерируются из одних параметров OpenAPI и передают одинаковые метод, query, заголовки и JSON.
Языки запросов
| Вкладка | Требования и HTTP-клиент |
|---|---|
| cURL | CLI curl с поддержкой --fail-with-body |
| PHP 8+ | PHP 8.0 или новее, расширения curl и json; strict_types, типизированный CurlHandle, без Composer-зависимостей |
| JavaScript / Node.js | Node.js 22+, встроенный fetch; файл .mjs, не браузер |
| Python | Python 3.10+, стандартный urllib.request, без pip-зависимостей |
| Go | Go 1.22+, стандартный net/http; файл main.go |
| Java | Java 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-клиент как проверку входящей подписи.