Fluxpays API

Создавайте платежи, запрашивайте их статус и получайте подписанные оповещения. Мерчантское API Fluxpays построено на REST, возвращает обычный JSON и авторизует каждый запрос Bearer-токеном; каждое оповещение подписано полем sign верхнего уровня.

Базовый URL: https://api.fluxpays.org·Версия: 2026-07-18

Введение

Мерчантское API Fluxpays — компактный REST-интерфейс поверх HTTPS: создание платежа, запрос его статуса, чтение баланса. Запросы и ответы — обычный JSON: для запроса достаточно Bearer-токена. Подписываются только оповещения (callbacks) о событиях — paid, refund и payout: каждая доставка несёт поле sign верхнего уровня, а её подлинность проверяется вашей солью.

Аутентификация

У магазина ДВА секрета, оба в Дашборде, в настройках воркспейса: API-ключ — токен, который передаётся как Bearer в заголовке Authorization каждого запроса, — и соль. Ключ авторизует запросы; соль нужна только для проверки поля sign входящих оповещений — по сети она никогда не передаётся. Оба секрета держите вне клиентского кода и публичных репозиториев.

Заголовок Bearer

Authorization: Bearer {token}

Соль (второй ключ в настройках) используется только для проверки поля sign входящих оповещений: HMAC-SHA256 от компактного JSON с отсортированными ключами верхнего уровня (без поля sign). По сети соль не передаётся.

Пример
curl https://api.fluxpays.org/balance \
  -H "Authorization: Bearer {token}"

Ошибки

Fluxpays использует стандартные коды ответов HTTP: 2xx — успех, 4xx — ошибка на стороне клиента, 5xx — ошибка на стороне Fluxpays. Успешные ответы — обычный JSON; ответы с ошибкой — простой текст с описанием причины (например, Invalid email, Payment not found).

СтатусНазваниеОписание
200OKУспех — JSON с запрошенными данными.
400Bad RequestНеверные параметры: некорректные amount или type, невалидный email, либо привязанный способ отключён у магазина.
401UnauthorizedОтсутствует или неверен заголовок Authorization: Bearer {token}.
403ForbiddenМагазин не активирован.
404Not FoundПлатёж не найден — orderID не существует или принадлежит другому магазину.
5xxServer ErrorЧто-то пошло не так на нашей стороне — повторите позже; если orderID не вернулся, ничего не создано.

Платежи

Создание платежа

Регистрирует заказ и возвращает ссылку на платёжную страницу, куда нужно перенаправить плательщика. Конкретный type жёстко привязывает ссылку к чекауту этого способа; "all" открывает выбор всех способов. Подпись не нужна — достаточно Bearer-токена. Когда плательщик оплатит заказ, подтверждение PAID придёт ПОДПИСАННЫМ оповещением (см. «Оповещения») — проверьте его sign, прежде чем отгружать товар.

POST/createPayment

Параметры тела запроса

ИмяТипОписание
amountnumberобязательныйСумма заказа в рублях — базовая; комиссия рассчитывается при оплате по выбранному плательщиком способу.
typeinteger | "all"обязательныйСпособ оплаты, к которому привязывается ссылка: 0 — СБП, 1 — Карта МИР, 2 — криптовалюта, 3 — Visa · Mastercard, 4 — СберПей. Передайте "all", чтобы плательщик выбрал любой включённый способ сам. Привязанный способ должен быть включён у магазина.
emailstringобязательныйEmail плательщика — отображается в деталях заказа и используется как реквизит списания для СБП / СберПей.
descriptionstringОписание заказа — показывается плательщику на платёжной странице.
langstringЯзык платёжной страницы: EN или RU.

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
orderIDstringID платежа (uuid) — используется в «Статусе платежа» и «Возврате платежа».
linkstringСсылка на платёжную страницу — перенаправьте на неё плательщика.
amountnumberСумма заказа в рублях, как зарегистрирована.
expiresintegerСрок действия ссылки, Unix ms — ссылка живёт 10 минут.
curl https://api.fluxpays.org/createPayment \
  -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "type": 0,
    "email": "[email protected]"
  }'
Ответ
{
  "status": "success",
  "orderID": "9fd37f19-2b3d-4424-aa90-78bdafd6ed03",
  "link": "https://fluxpays.org/pay/9fd37f19-2b3d-4424-aa90-78bdafd6ed03",
  "amount": 1000,
  "expires": 1784404593330
}
Возвращает: JSON с orderID, платёжной ссылкой и сроком её действия (ссылка живёт 10 минут).

Статус платежа

Возвращает текущее состояние платежа, созданного вашим магазином (чужие платежи недоступны). Опрашивайте сколько угодно — авторитетное, подписанное подтверждение приходит оповещением; опрос используйте как запасной вариант, если оно не пришло в течение 5 минут.

POST/paymentStatus

Параметры тела запроса

ИмяТипОписание
orderIDstringобязательныйorderID из ответа «Создание платежа».

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
paymentobjectОбъект платежа.
payment.orderIDstringID платежа (uuid).
payment.statusstringWAIT, PAID, CANCELED или REFUNDED.
payment.amountnumberСписанная сумма в рублях.
payment.feenumberКомиссия в рублях по использованному способу.
payment.methodstringСпособ, которым реально оплатил плательщик.
payment.demobooleantrue для демо-платежей (тестовых).
payment.createdintegerДата создания, Unix ms.
payment.paidDateintegerДата оплаты, Unix ms — null, пока платёж в статусе WAIT.
curl https://api.fluxpays.org/paymentStatus \
  -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"orderID":"9fd37f19-2b3d-4424-aa90-78bdafd6ed03"}'
Ответ
{
  "status": "success",
  "payment": {
    "orderID": "9fd37f19-2b3d-4424-aa90-78bdafd6ed03",
    "status": "PAID",
    "amount": 1000,
    "fee": 100,
    "method": "СБП",
    "demo": false,
    "created": 1784403993000,
    "paidDate": 1784404120000
  }
}
Возвращает: JSON с платежом: status — WAIT, PAID, CANCELED или REFUNDED; amount — сколько списано с плательщика; fee — комиссия. Авторитетное, подписанное подтверждение — оповещение.

Возврат платежа

Возвращает оплаченный (PAID) платёж — тот же процесс, что запускает кнопка возврата в Дашборде: PSP возвращает деньги плательщику, зачисленная сумма списывается с баланса магазина, платёж переходит в REFUNDED. Идемпотентно: повторный возврат уже возвращённого (REFUNDED) платежа просто вернёт его текущее состояние. Криптоплатежи через API не возвращаются — верните средства вручную. Если асинхронный возврат позже не пройдёт на стороне PSP, платёж откатывается в PAID (refundStatus ERROR), а баланс восстанавливается. Итоговый, проверяемый результат придёт ПОДПИСАННЫМ оповещением о возврате — проверьте его sign.

POST/refundPayment

Параметры тела запроса

ИмяТипОписание
orderIDstringобязательныйorderID оплаченного платежа, который нужно вернуть.

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
payment.statusstringREFUNDED, как только возврат принят. Откатывается в PAID, если PSP позже не проведёт асинхронный возврат.
payment.refundStatusstringPROCESSING — PSP принял возврат и завершает его асинхронно; SUCCESS — деньги вернулись плательщику. Итоговое состояние также придёт вебхуком о возврате.
curl https://api.fluxpays.org/refundPayment \
  -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"orderID":"9fd37f19-2b3d-4424-aa90-78bdafd6ed03"}'
Ответ
{
  "status": "success",
  "payment": {
    "orderID": "9fd37f19-2b3d-4424-aa90-78bdafd6ed03",
    "status": "REFUNDED",
    "refundStatus": "PROCESSING",
    "amount": 1000,
    "fee": 100,
    "method": "СБП",
    "demo": false,
    "created": 1784403993000,
    "refundDate": 1784490210000
  }
}
Возвращает: JSON с платежом: status REFUNDED, refundStatus PROCESSING или SUCCESS и refundDate. Ошибки — обычный текст: 400 (недостаточно средств, PSP отклонил возврат) или 404 Payment not found.

Баланс

Получить баланс

Возвращает все счета кошелька магазина (RUB, USD, EUR, KZT) с детализацией: available — зачисленные деньги, доступные к трате и выводу прямо сейчас; hold — оплаченные платежи в 24-часовом холде, их зачислит суточный релиз (только RUB); balance — их сумма. Поле balance на верхнем уровне дублирует available по RUB для старых интеграций.

GET/balance

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
currencystringВалюта верхнеуровневого поля balance (RUB) — для старых интеграций.
balancenumberДоступный RUB, продублирован на верхнем уровне для старых интеграций.
accountsarrayМассив счетов — по записи на валюту кошелька.
accounts.*objectЭлемент массива.
accounts.*.currencystringВалюта счёта: RUB, USD, EUR или KZT.
accounts.*.availablenumberЗачисленные деньги — можно тратить и выводить прямо сейчас.
accounts.*.holdnumberОплаченное в 24-часовом холде (только RUB).
accounts.*.balancenumberavailable + hold.
curl https://api.fluxpays.org/balance \
  -H "Authorization: Bearer {token}"
Ответ
{
  "status": "success",
  "currency": "RUB",
  "balance": 125430.5,
  "accounts": [
    { "currency": "RUB", "available": 125430.5, "hold": 2200, "balance": 127630.5 },
    { "currency": "USD", "available": 14.16, "hold": 0, "balance": 14.16 },
    { "currency": "EUR", "available": 0, "hold": 0, "balance": 0 },
    { "currency": "KZT", "available": 0, "hold": 0, "balance": 0 }
  ]
}
Возвращает: JSON с массивом accounts — по записи на валюту с available, hold и итогом.

Выплаты

Выплаты создаются прямо из API — СБП, Карта МИР и USDT TRC-20. Метод сам определяет счёт, с которого уходят деньги: СБП и Карта МИР списываются с рублёвого баланса, USDT — с долларового, поэтому currency в запросе должна совпадать с этим счётом. Комиссия, минимальная и максимальная суммы берутся из тарифов вашего воркспейса — тех же, что показаны в Дашборде. Выплаты доступны сразу после активации магазина; при необходимости отдельный способ может быть отключён для воркспейса, тогда запрос вернёт METHOD_DISABLED. Итоговый статус приходит на ваш callback-URL подписанным вебхуком (см. «Вебхуки») либо его можно запросить методом «Статус выплаты». Здесь же — справочники для интеграции: курсы валют и банки-участники СБП.

Создание выплаты

Создаёт выплату на указанные реквизиты. Сумма amount — брутто: она списывается с баланса целиком, комиссия тарифа удерживается из неё, получателю уходит net. Комиссия состоит из процента и фиксированной части; для USDT фиксированная часть — это комиссия сети TRC-20 (по умолчанию 3.5 USDT), и обе настраиваются для вашего воркспейса. Набор обязательных реквизитов зависит от method: для sbp — phone и bankId, для mir — cardNumber и cardHolder, для usdt — address. Деньги резервируются в момент запроса, поэтому повторный вызов создаст вторую выплату — используйте externalId, чтобы сверять их со своими записями.

POST/createPayout

Параметры тела запроса

ИмяТипОписание
methodstringобязательныйСпособ выплаты: sbp, mir или usdt (USDT в сети TRC-20).
currencystringобязательныйСчёт списания. Должен совпадать со счётом способа: RUB для sbp и mir, USD для usdt.
amountnumberобязательныйСумма списания с баланса (брутто). Комиссия удерживается из неё.
phonestringТолько sbp: телефон получателя в СБП.
bankIdstringТолько sbp: ID банка получателя из метода «Банки СБП».
cardNumberstringТолько mir: номер карты МИР.
cardHolderstringТолько mir: ФИО держателя карты — обязательное поле для карточных выплат.
addressstringТолько usdt: адрес кошелька USDT в сети TRC-20.
externalIdstringВаш собственный идентификатор выплаты — возвращается в ответе, в статусе и в вебхуке.
descriptionstringПроизвольный комментарий — сохраняется в истории операций воркспейса.

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
payoutIDintegerID выплаты в Fluxpays — с ним запрашивается статус.
statestringprocessing — выплата передана провайдеру; queued — принята и ждёт свободный канал.
amountnumberСумма, списанная с баланса (брутто).
currencystringВалюта счёта списания.
feenumberУдержанная комиссия по тарифу воркспейса.
netnumberСумма к зачислению получателю: amount минус комиссия (процент плюс фиксированная часть).
externalIdstringВаш идентификатор из запроса, либо null.
curl https://api.fluxpays.org/createPayout \
  -X POST \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "sbp",
    "currency": "RUB",
    "amount": 15000,
    "phone": "+79001234567",
    "bankId": "100000000111",
    "externalId": "payout-2041"
  }'
Ответ
{
  "status": "success",
  "payoutID": 4812,
  "state": "processing",
  "amount": 15000,
  "currency": "RUB",
  "fee": 525,
  "net": 14475,
  "externalId": "payout-2041"
}
Возвращает: JSON с payoutID, состоянием выплаты и разбивкой суммы: сколько списано, сколько удержано комиссией и сколько уйдёт получателю. При ошибке — поля error и message: WRONG_WALLET, METHOD_DISABLED, MIN_AMOUNT, MAX_AMOUNT, INSUFFICIENT, CHANNEL_UNAVAILABLE.

Статус выплаты

Возвращает текущее состояние выплаты. Fluxpays сам опрашивает провайдера, поэтому статус обновляется без вашего участия — этот метод нужен, если вы не полагаетесь на вебхуки. Состояние failed означает, что деньги уже возвращены на баланс воркспейса.

GET/payoutStatus

Параметры пути и запроса

ИмяТипОписание
payoutIDintegerобязательныйID выплаты, полученный при её создании.

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
payoutIDintegerID выплаты в Fluxpays.
statestringqueued — ждёт канал; processing — у провайдера; paid — доставлена; failed — не прошла, деньги возвращены на баланс.
amountnumberСумма, списанная с баланса (брутто).
netnumberСумма к зачислению получателю.
currencystringВалюта счёта списания.
destinationstringРеквизиты получателя в том виде, в каком они отображаются в истории операций.
externalIdstringВаш идентификатор из запроса, либо null.
createdintegerВремя создания выплаты, unix-время в миллисекундах.
curl "https://api.fluxpays.org/payoutStatus?payoutID=4812" \
  -H "Authorization: Bearer {token}"
Ответ
{
  "status": "success",
  "payoutID": 4812,
  "state": "paid",
  "amount": 15000,
  "net": 14475,
  "currency": "RUB",
  "destination": "СБП · Сбербанк · +79001234567",
  "externalId": "payout-2041",
  "created": 1784404593330
}
Возвращает: JSON с состоянием выплаты, суммами и реквизитами получателя.

Курсы валют

Возвращает текущие курсы валют — сколько рублей стоит 1 единица валюты. Источник — ЦБ РФ, значения кэшируются на час. Это курс ВАШЕГО воркспейса: если для него задана наценка к курсу, она уже учтена, поэтому обмен пройдёт ровно по этому числу. USDT повторяет курс USD — именно этот курс применяется к операциям с Tether.

GET/rates

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
USDnumberКурс доллара США, рублей за 1 USD.
EURnumberКурс евро, рублей за 1 EUR.
KZTnumberКурс казахстанского тенге, рублей за 1 KZT.
USDTnumberКурс USDT, рублей за 1 USDT — применяется к операциям с Tether.
curl https://api.fluxpays.org/rates \
  -H "Authorization: Bearer {token}"
Ответ
{
  "status": "success",
  "USD": 79.42,
  "EUR": 90.1,
  "KZT": 0.16,
  "USDT": 79.4
}
Возвращает: JSON с полем на каждую валюту (USD, EUR, KZT, USDT) — рублей за 1 единицу.

Банки СБП

Возвращает банки-участники СБП, доступные для выплат по СБП. id банка указывается в реквизитах выплаты. Список меняется редко — кэшируйте его на своей стороне, обновления раз в сутки достаточно.

GET/sbpBanks

Формат ответа: JSON

Схема успешного ответа

ИмяТипОписание
banksarrayМассив с данными банков, подключённых к системе быстрых платежей (СБП).
banks.*objectЭлемент массива.
banks.*.idnumberID банка в системе быстрых платежей (СБП) — источник: справочник НСПК.
banks.*.namestringНаименование банка.
banks.*.logostringURL логотипа банка (НСПК).
curl https://api.fluxpays.org/sbpBanks \
  -H "Authorization: Bearer {token}"
Ответ
{
  "status": "success",
  "banks": [
    { "id": 100000000004, "name": "Т-Банк", "logo": "https://qr.nspk.ru/proxyapp/logo/bank100000000004.png" },
    { "id": 100000000111, "name": "Сбербанк", "logo": "https://qr.nspk.ru/proxyapp/logo/bank100000000111.png" },
    { "id": 100000000008, "name": "АЛЬФА-БАНК", "logo": "https://qr.nspk.ru/proxyapp/logo/bank100000000008.png" }
  ]
}
Возвращает: JSON с массивом banks — id, отображаемое название и логотип каждого банка (данные из справочника НСПК).

Оповещения

Fluxpays отправляет все события на ОДИН callback-URL (задаётся в Дашборде, в настройках воркспейса) в едином формате тела: поле event говорит, что произошло — paid, refund или payout, — а остальные поля несут данные этого события. Каждая доставка подписана: поле sign верхнего уровня — это HMAC-SHA256 (hex) от полезной нагрузки, сериализованной компактным JSON с ключами верхнего уровня, отсортированными по алфавиту, без поля sign (вложенные объекты и массивы сохраняют свой порядок), ключ — ваша СОЛЬ. Соберите канонический JSON из разобранных полей, пересчитайте HMAC и сравните, прежде чем доверять данным: URL может узнать кто угодно, но соль есть только у Fluxpays. Отвечайте 200 для подтверждения.

Уведомление PAID

Отправляется, когда плательщик завершил оплату. Поля описывают проведённый платёж; amount — сколько реально списано с плательщика (база + комиссия, если её платит покупатель), fee — комиссия использованного способа.

POSThttps://your-site.com/webhook

Параметры тела запроса

ИмяТипОписание
eventstringВсегда "paid" для этой доставки — по полю event различаются три вида вебхуков.
orderIDstringID платежа (uuid) — тот же orderID, что вернуло «Создание платежа».
statusstringДля этого события всегда PAID.
amountnumberСписанная сумма в рублях.
feenumberКомиссия в рублях по способу, которым оплатил плательщик.
methodstringСпособ, которым реально оплатил плательщик (например, СБП, Карта МИР).
demobooleantrue для демо-платежей (тестовых) — никогда не отгружайте реальный товар по демо-платежу.
# What Fluxpays sends to your callback URL:
POST /webhook HTTP/1.1
Host: your-site.com
Content-Type: application/json

# sign = HMAC-SHA256_hex(other fields as sorted-key compact JSON, SALT)
{"event":"paid","orderID":"9fd37f19-...","status":"PAID",
 "amount":1000,"fee":100,"method":"СБП","demo":false,
 "sign":"84fa01d7c25b9e360dc47f18..."}
Ответ
{
  "event": "paid",
  "orderID": "9fd37f19-2b3d-4424-aa90-78bdafd6ed03",
  "status": "PAID",
  "amount": 1000,
  "fee": 100,
  "method": "СБП",
  "demo": false,
  "sign": "84fa01d7c25b9e360dc47f18a6e5923bf1708c4d5e2ab96327d90e5fb1c483a6"
}

Уведомление о возврате

Отправляется, когда возврат принят (status REFUNDED, refundStatus PROCESSING или SUCCESS), и повторно, когда асинхронный возврат завершается: refundStatus SUCCESS — деньги вернулись плательщику, либо status PAID + refundStatus ERROR — PSP не смог вернуть деньги, и платёж откатился в PAID. Поле event всегда "refund" — по нему отличайте эту доставку от вебхуков платежей и выплат на том же URL. Подпись sign проверяйте тем же способом, что и у платежей, и отвечайте 200 для подтверждения.

POSThttps://your-site.com/webhook

Параметры тела запроса

ИмяТипОписание
eventstringВсегда "refund" для этой доставки.
orderIDstringID платежа (uuid) — тот же orderID, что вернуло «Создание платежа».
statusstringТекущий статус платежа: REFUNDED, либо PAID, если возврат не прошёл и откатился.
refundStatusstringPROCESSING — принят, финальная доставка придёт позже; SUCCESS — деньги вернулись плательщику; ERROR — PSP не провёл возврат, платёж снова PAID, баланс восстановлен.
amountnumberСумма возврата в рублях — столько получит обратно плательщик.
demobooleantrue для демо-платежей (тестовых) — реальные деньги не двигались ни туда, ни обратно.
# What Fluxpays sends to your callback URL (the same URL as
# payments — the "event" field tells the deliveries apart):
POST /webhook HTTP/1.1
Host: your-site.com
Content-Type: application/json

# sign = HMAC-SHA256_hex(other fields as sorted compact JSON, SALT)
{"event":"refund","orderID":"9fd37f19-...","status":"REFUNDED",
 "refundStatus":"SUCCESS","amount":1000,"demo":false,
 "sign":"d21c84e0f67aba4c19f7d02e..."}
Ответ
{
  "event": "refund",
  "orderID": "9fd37f19-2b3d-4424-aa90-78bdafd6ed03",
  "status": "REFUNDED",
  "refundStatus": "SUCCESS",
  "amount": 1000,
  "demo": false,
  "sign": "d21c84e0f67aba4c19f7d02e85b3647c90e1f8a2563b9d40c7e2185fa6039b5d"
}

Уведомление о выплате

Отправляется, когда выплата из кошелька выполнена (SUCCESS) или отклонена (ERROR — причина приходит в дополнительном поле error). Поле event всегда "payout" — по нему отличайте эту доставку от вебхука платежа на том же URL. Подпись sign проверяйте тем же способом, что и у платежей, и отвечайте 200 для подтверждения.

POSThttps://your-site.com/webhook

Параметры тела запроса

ИмяТипОписание
eventstringВсегда "payout" для этой доставки.
payoutIDintegerID выплаты — тот же номер, что показывает Дашборд в разделе «Выплаты».
statusstringSUCCESS — деньги ушли из кошелька; ERROR — выплата отклонена, причина в поле error.
amountnumberСумма выплаты в валюте выплаты.
currencystringКод валюты выплаты (например, RUB).
destinationstringКуда ушли деньги, в читаемом виде — название сохранённого реквизита и маскированный номер.
externalIdstringВаш идентификатор из «Создания выплаты». Приходит только у выплат, созданных через API.
# What Fluxpays sends to your callback URL (the same URL as
# payments — the "event" field tells the deliveries apart):
POST /webhook HTTP/1.1
Host: your-site.com
Content-Type: application/json

# sign = HMAC-SHA256_hex(other fields as sorted compact JSON, SALT)
{"event":"payout","payoutID":1042,"status":"SUCCESS","amount":2500,
 "currency":"RUB","destination":"Основная карта · •••• 9718",
 "sign":"f1a83c05d9427b6e08c1f5a3..."}
Ответ
{
  "event": "payout",
  "payoutID": 1042,
  "status": "SUCCESS",
  "amount": 2500,
  "currency": "RUB",
  "destination": "Основная карта · •••• 9718",
  "sign": "f1a83c05d9427b6e08c1f5a3962d4b7e5019c8d2374a6f0be95d13c8a20f764d"
}

Подпись оповещений

Fluxpays подписывает каждое оповещение — paid, refund и payout — полем sign. Каноника — полезная нагрузка, сериализованная в компактный JSON с отсортированными по алфавиту ключами верхнего уровня, без поля sign (без пробелов; юникод и слеши не экранируются); HMAC-SHA256 этой строки вашей солью в hex и есть sign. Проверяйте подпись, прежде чем обрабатывать событие: соберите канонику из разобранного тела и сравните хеши за константное время. API-запросы и ответы не подписываются.

Контрольный пример

Данные

{"amount":1000,"email":"[email protected]","type":0}

Соль

example

sign

2a450c52c29d425f834e8c395bcf36fdbcd17a799fe0d9b47f47ea5267eed8a6

Прогоните эти данные и соль через свою реализацию — если sign совпал, ваша каноника корректна байт в байт. Вложенные объекты и массивы сериализуются как есть (порядок их ключей сохраняется); сортируется только верхний уровень.

Как проверить оповещение

const crypto = require("node:crypto");

// canonical = compact JSON of every field except "sign",
// top-level keys sorted; HMAC keyed with your merchant SALT
function verifySign(body, salt) {
  const { sign = "", ...fields } = body;
  const sorted = Object.fromEntries(
    Object.keys(fields).sort().map(k => [k, fields[k]]));
  const expected = crypto.createHmac("sha256", salt)
    .update(JSON.stringify(sorted), "utf8").digest("hex");
  return sign.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sign), Buffer.from(expected));
}

if (!verifySign(req.body, SALT)) throw new Error("bad signature");

© 2026 Fluxpays — справочник API v2026-07-18