00
Архитектура средств и баланса
При регистрации мерчант не получает блокчейн-кошелёк и не передаёт seed phrase. Для каждого счёта платформа выдаёт уникальный депозитный адрес под своим контролем. После AML 98% сразу появляются в ledger мерчанта, но сама криптовалюта не переводится с каждого адреса немедленно.
ДепозитAML98% / 2% ledgerочередьРучной сбор
- Баланс ведётся отдельно по сети и активу: USDT TRC-20 не смешивается с USDT SPL.
- Автоматическая консолидация отключена: сбор запускается только отдельным ручным действием.
- Перед ручным запуском система проверяет, что комиссия Nova Pay покрывает сетевую стоимость с запасом.
- В TRON используется центральный Energy-пул: ресурс делегируется депозитным адресам перед сбором.
- Высокорисковый перевод остаётся на изолированном адресе, блокируется для вывода на 21 день и уходит на ручную проверку.
- Мерчант может запросить вывод в любое время; на первом этапе заявка одобряется вручную.
01
Быстрый старт
- Зарегистрируйте проект и сохраните показанные один раз
API key и webhook secret. - В настройках укажите публичный HTTPS webhook URL.
- Создайте счёт через API и перенаправьте клиента на
checkoutUrl. - Меняйте заказ только после проверенного события
invoice.paid. - Сохраняйте
X-Gateway-Delivery, чтобы не обработать повторную доставку дважды.
Ваш backendPOST /v1/invoicesHosted checkoutinvoice.paidВаш webhook
02
Авторизация
Передавайте API-ключ только с вашего backend. Не помещайте его в браузерный JavaScript, мобильное приложение или URL.
Authorization: Bearer np_test_...
Ключ можно перевыпустить в настройках. Старый ключ перестаёт работать сразу. Для каждого запроса создания требуется отдельный Idempotency-Key длиной 8–128 символов.
POST/v1/invoices
Создать счёт
curl -X POST https://gateway.kurazolotaya.site/v1/invoices \
-H "Authorization: Bearer np_test_..." \
-H "Idempotency-Key: order-1001-attempt-1" \
-H "Content-Type: application/json" \
-d '{
"externalId": "order-1001",
"network": "TRON",
"asset": "USDT",
"amount": "10.50",
"successUrl": "https://partner.example/payment/success",
"failureUrl": "https://partner.example/payment/failed",
"metadata": { "customerId": "42" }
}'
Поля запроса
externalIdstring · requiredID заказа в вашей системе, до 100 символов.
networkenum · requiredTRON, SOLANA, ETHEREUM, BSC, POLYGON или TON.
assetenum · requiredНа первом этапе поддерживается USDT.
amountdecimal · requiredОт динамического минимума выбранной сети до 10 000, максимум 6 знаков после запятой.
successUrl / failureUrlURL · optionalСтраницы возврата пользователя.
metadataobject · optionalВаши служебные данные; не передавайте секреты.
Ответ 201
{
"ok": true,
"invoice": {
"id": "inv_...",
"externalId": "order-1001",
"network": "TRON",
"asset": "USDT",
"merchantAmount": "10.500000",
"networkFee": "0.000000",
"expectedAmount": "10.500000",
"minimumAmount": "1.000000",
"collectionStrategy": "ENERGY_POOL_BATCH",
"collectionProtected": true,
"status": "PENDING",
"depositAddress": "TEST_ONLY_TRON_...",
"checkoutUrl": "https://gateway.kurazolotaya.site/pay/inv_...",
"expiresAt": "2026-09-09T12:00:00.000Z"
},
"idempotentReplay": false
}
ИдемпотентностьПовтор с тем же ключом вернёт исходный счёт с HTTP 200 и idempotentReplay: true, даже если тело запроса изменилось.
GET/v1/invoices/{invoiceId}
Получить текущий статус
curl https://gateway.kurazolotaya.site/v1/invoices/inv_... \
-H "Authorization: Bearer np_test_..."
Получить последние счета проекта: GET /v1/invoices?limit=50. API-ключ одного партнёра никогда не даёт доступ к счетам другого.
Публичная страница checkout доступна по /pay/{invoiceId}. Ограниченный публичный статус — /public/invoices/{invoiceId}.
TEST
Проверка сценариев в sandbox
Те же действия доступны кнопками в карточке счёта. Для автоматического теста используйте API:
POST /v1/sandbox/invoices/{id}/detect
{"amount":"10.50"}
POST /v1/sandbox/invoices/{id}/aml
{"decision":"CLEAR"} // или BLOCKED
POST /v1/sandbox/invoices/{id}/settle
{}
Рекомендуемый тест: точная сумма → недоплата → доплата → переплата → AML block → просроченный платёж → повтор webhook. Sandbox-методы отсутствуют в production-контракте.
03
Подписанные webhook
Nova Pay отправляет JSON методом POST. Ответьте любым HTTP 2xx не позднее 7 секунд. При ошибке доставка повторяется с увеличивающейся задержкой, максимум 8 попыток.
X-Gateway-DeliveryУникальный ID доставки и ключ дедупликации.
X-Gateway-EventНапример, invoice.paid.
X-Gateway-TimestampUnix timestamp; рекомендуем окно не более 5 минут.
X-Gateway-Signaturev1=<hex HMAC-SHA256>.
Проверка подписи в Node.js
const crypto = require("node:crypto");
function verify(rawBody, headers, secret) {
const timestamp = headers["x-gateway-timestamp"];
const actual = headers["x-gateway-signature"];
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const hex = crypto.createHmac("sha256", secret)
.update(timestamp + "." + rawBody)
.digest("hex");
const expected = "v1=" + hex;
const a = Buffer.from(actual || "");
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Событие invoice.paid
{
"id": "evt_...",
"type": "invoice.paid",
"createdAt": "2026-09-09T12:00:01.000Z",
"data": { "invoice": { "id": "inv_...", "status": "PAID" } }
}
Правильный порядокСначала проверьте timestamp и HMAC по исходному телу, затем зафиксируйте delivery ID в уникальном поле и только после этого меняйте заказ.
04
Статусы счёта
PENDINGОжидается перевод.
PARTIALLY_PAIDНедоплата; зачисления нет.
AML_REVIEWСумма получена, вывод заблокирован до проверки.
AML_BLOCKEDВысокий риск; доступный баланс не создаётся.
PAIDAML пройден, 98% зачислены в ledger, сбор может ожидать пакета.
SETTLEDОнчейн-средства собраны в экономически безопасном пакете.
EXPIREDПять минут истекли, счёт закрыт.
LATE_PAYMENT_REVIEWПоздний перевод изолирован для ручного решения.
05
Динамический минимум и комиссии
merchantAmount = expectedAmount: клиент платит ровно сумму заказа, без доплаты Nova Pay.networkFee для новых счетов равен нулю; кошелёк клиента оплачивает только свой обычный gas.minimumAmount покрывает оценку одного исходящего сбора с конкретного депозитного адреса и запас 50%. Пакетная очередь не делит эту стоимость на число счетов.- Текущие защитные пороги: TRON — 18,75; Solana — 0,75; Ethereum — 225; BSC — 3,75; Polygon — 1,50; TON — 1,50 USDT. Перед mainnet они обновляются по реальной fee telemetry.
- После AML 2% учитываются как комиссия Nova Pay, 98% — в
partnerNet. - Автоматический сбор отключён. При ручном запуске система проверяет, что комиссия именно этого счёта покрывает сетевую стоимость с запасом.
- Недоплата не создаёт доступный баланс; переплата отражается в
overpaymentAmount. - Платёж после истечения срока не зачисляется автоматически.
!
HTTP-коды и ошибки
400Некорректное поле, сумма, сеть или Idempotency-Key.
401API-ключ отсутствует или недействителен.
404Счёт не найден либо принадлежит другому партнёру.
409Операция не разрешена в текущем статусе.
429Превышен лимит запросов.
5xxВременная ошибка; повторите запрос с тем же Idempotency-Key.
{
"ok": false,
"code": "invalid_amount",
"error": "Сумма должна быть от 1 до 10000 USDT."
}
06
Чек-лист безопасности
- Хранить API key и webhook secret только в Secret Manager или переменных backend.
- Всегда использовать HTTPS и проверять подпись по сырому телу запроса.
- Не выполнять зачисление по возврату пользователя на successUrl.
- Доверять только событию
invoice.paid после успешной HMAC-проверки. - Сделать обработчик транзакционным и идемпотентным.
- При утечке немедленно перевыпустить ключи в кабинете.
Переход в productionПотребуются production RPC, AML-провайдер, HSM/Vault signer, gas station, подтверждение владения кошельками и реальные canary-платежи. Опубликованные ранее ключи использовать нельзя.