Назад к блогу
08.04.2026 16:17:09

Интеграция Binance Pay v3 в Битрикс: создание платежа, webhook и пополнение баланса пользователя

Интеграция Binance Pay с сайтом на 1С-Битрикс может использоваться не только для оплаты обычных заказов, но и для пополнения внутреннего баланса пользователя. Такой сценарий часто встречается в личных кабинетах, сервисах, маркетплейсах, форумах с платными функциями, B2B-порталах и проектах, где пользователь заранее вносит средства, а потом расходует их внутри сайта.

На первый взгляд задача выглядит просто: пользователь ввел сумму, оплатил через Binance Pay, а сайт увеличил его баланс. Но технически это полноценная платежная интеграция: нужно создать ордер, подписать запрос, сохранить платеж в базе, принять webhook, проверить статус оплаты, защититься от повторной обработки и только после этого обновить пользовательское поле баланса.

Такие задачи относятся к кастомной разработке на PHP и Битрикс. Если нужно подключить оплату, доработать личный кабинет, исправить обработку webhook или связать платежную систему с внутренним балансом, это можно реализовать в рамках услуги доработки Bitrix и PHP-задачи.

Как работает схема пополнения баланса

Общий процесс интеграции Binance Pay v3 можно разделить на несколько этапов:

  1. Пользователь вводит сумму пополнения на сайте.
  2. Сервер создает платежный ордер в Binance Pay.
  3. Binance возвращает данные для оплаты: ссылку, QR-код или deeplink.
  4. Пользователь оплачивает через приложение или платежную страницу Binance.
  5. Binance отправляет webhook на сайт.
  6. Сервер проверяет статус платежа и находит внутреннюю запись заказа.
  7. Если платеж успешный и ранее не был обработан, баланс пользователя увеличивается.
  8. Фронтенд через AJAX проверяет статус и закрывает окно оплаты.

Важно: баланс пользователя нельзя обновлять сразу после создания платежа или открытия QR-кода. Деньги нужно зачислять только после подтверждения оплаты через webhook.

Создание платежа через Binance Pay v3

Для создания платежа используется endpoint:

POST /binancepay/openapi/v3/order

Минимальный payload для пополнения баланса может выглядеть так:

{
    "merchantTradeNo": "ORDER123456789",
    "orderAmount": "10.00",
    "currency": "USDT",
    "env": {
        "terminalType": "WEB"
    },
    "description": "Balance Top-up",
    "goodsDetails": [
        {
            "goodsType": "01",
            "goodsCategory": "D000",
            "referenceGoodsId": "balance_topup",
            "goodsName": "Balance Top-up"
        }
    ],
    "returnUrl": "https://example.com/success",
    "cancelUrl": "https://example.com/cancel"
}

В этом запросе важно правильно сформировать merchantTradeNo. Это внутренний номер платежа, по которому потом можно связать webhook Binance с записью в Битрикс.

Для пополнения баланса лучше использовать уникальный ID операции, а не просто ID пользователя. Например:

BPAY1234567890

Такой номер можно сохранить в Highload-блоке и использовать как ключ для поиска платежа после webhook.

Требования к merchantTradeNo

У Binance Pay есть важные ограничения к полю merchantTradeNo:

  • только буквы и цифры;
  • без пробелов, дефисов и специальных символов;
  • максимальная длина — 32 символа;
  • значение должно быть уникальным для платежа.

Если сформировать номер с неподходящими символами или слишком длинной строкой, Binance может отклонить запрос на создание платежа.

Подпись запроса Binance Pay

Для обращения к Binance Pay запрос нужно подписывать. Подпись формируется из timestamp, nonce и JSON-тела запроса.

$signaturePayload = $timestamp . "\n" . $nonce . "\n" . $jsonPayload . "\n";

$signature = strtoupper(hash_hmac('SHA512', $signaturePayload, $secretKey));

Важно, чтобы в подпись попадал именно тот JSON, который уходит в запрос. Если сначала подписать один payload, а потом отправить другой формат JSON, подпись не пройдет.

Заголовки запроса:

Content-Type: application/json
BinancePay-Timestamp: timestamp
BinancePay-Nonce: nonce
BinancePay-Signature: signature
BinancePay-Certificate-SN: API_KEY

На практике ошибки подписи часто возникают из-за неправильного timestamp, лишних переносов, повторной генерации JSON, неверного secret key или использования не того API key.

Что нужно сохранить в Битрикс при создании платежа

После успешного создания ордера в Binance Pay нужно сохранить внутреннюю запись платежа. Для этого удобно использовать Highload-блок.

Минимальный набор полей:

UF_ORDER_ID
UF_USER_ID
UF_AMOUNT
UF_PAID

Но в реальном проекте лучше хранить больше технических данных:

  • UF_ORDER_ID — внутренний номер платежа, который передается как merchantTradeNo;
  • UF_USER_ID — ID пользователя Битрикс;
  • UF_AMOUNT — сумма пополнения;
  • UF_CURRENCY — валюта платежа, например USDT;
  • UF_PAID — флаг успешной оплаты;
  • UF_STATUS — технический статус платежа;
  • UF_RESPONSE — ответ Binance при создании платежа;
  • UF_WEBHOOK — последний webhook от Binance;
  • UF_CREATED_AT — дата создания операции;
  • UF_PAID_AT — дата успешной оплаты.

Пример базовой записи:

$entityDataClass::add([
    'UF_ORDER_ID' => $orderId,
    'UF_USER_ID' => $userId,
    'UF_AMOUNT' => $amount,
    'UF_PAID' => false
]);

Если на проекте уже есть личный кабинет, внутренняя валюта, история пополнений или платные функции, структуру хранения лучше продумать заранее. Это уже не просто подключение платежной кнопки, а доработка бизнес-логики на Битрикс.

Webhook Binance Pay

После оплаты Binance отправляет уведомление на callback URL сайта. Пример структуры:

{
    "bizType": "PAY",
    "data": "{...}",
    "bizStatus": "PAY_SUCCESS"
}

Важный момент: поле data приходит как строка JSON. Его нужно декодировать отдельно.

$data = json_decode($rawData, true);
$innerData = json_decode($data['data'], true);

Проверка успешного платежа может выглядеть так:

if ($data['bizType'] === 'PAY' && $data['bizStatus'] === 'PAY_SUCCESS') {
    // обработка успешной оплаты
}

Но одной проверки статуса недостаточно. В рабочей интеграции нужно дополнительно:

  • получить merchantTradeNo из вложенного data;
  • найти внутреннюю запись платежа в Highload-блоке;
  • проверить, не был ли платеж уже обработан;
  • сравнить сумму и валюту;
  • сохранить webhook в лог;
  • только после этого пополнить баланс пользователя.

Почему важна защита от повторного webhook

Webhook может прийти повторно. Это нормальная ситуация для платежных систем: сервис может отправить уведомление еще раз, если не получил корректный ответ или повторяет доставку события.

Поэтому перед обновлением баланса обязательно нужно проверить флаг UF_PAID.

if ($order['UF_PAID']) {
    exit;
}

Без такой проверки пользовательский баланс может быть пополнен дважды по одному и тому же платежу. Для платежных интеграций это критическая ошибка.

Поиск платежа в Highload-блоке

После получения webhook нужно найти внутреннюю запись платежа по merchantTradeNo.

$order = $entityDataClass::getList([
    'filter' => [
        'UF_ORDER_ID' => $merchantTradeNo
    ]
])->fetch();

Если запись не найдена, баланс обновлять нельзя. В этом случае нужно залогировать входящий webhook и вернуть технический ответ.

Также полезно проверять, что UF_USER_ID существует, пользователь активен, а сумма платежа совпадает с ожидаемой суммой в базе.

Обновление баланса пользователя

В простом варианте баланс пользователя может храниться в пользовательском поле, например UF_BALANCE. После успешного webhook получаем пользователя, прибавляем сумму и сохраняем новое значение.

$rsUser = CUser::GetByID($userId);
$arUser = $rsUser->Fetch();

$newBalance = (float)$arUser['UF_BALANCE'] + (float)$amount;

$user = new CUser();

$user->Update($userId, [
    'UF_BALANCE' => $newBalance
]);

После этого платеж нужно отметить как обработанный:

$entityDataClass::update($order['ID'], [
    'UF_PAID' => true
]);

В более надежной реализации лучше обновлять не только UF_PAID, но и статус, дату оплаты, исходный webhook и итоговый баланс после операции.

$entityDataClass::update($order['ID'], [
    'UF_PAID' => true,
    'UF_STATUS' => 'PAY_SUCCESS',
    'UF_WEBHOOK' => $rawData,
    'UF_PAID_AT' => new \Bitrix\Main\Type\DateTime()
]);

Что важно учесть при работе с балансом

Пополнение баланса — это финансовая операция внутри сайта. Поэтому лучше не ограничиваться простым увеличением пользовательского поля.

В нормальной архитектуре желательно хранить историю операций:

  • сумма пополнения;
  • валюта платежа;
  • пользователь;
  • номер операции;
  • статус оплаты;
  • ответ Binance;
  • дата создания;
  • дата оплаты;
  • баланс до операции;
  • баланс после операции.

Это помогает разбираться в спорных ситуациях: пользователь оплатил, но баланс не обновился; webhook не дошел; платеж пришел повторно; сумма не совпала; администратору нужно проверить историю начислений.

Проверка статуса оплаты через AJAX

После создания платежа пользователь обычно видит модальное окно с QR-кодом или ссылкой на Binance Pay. Чтобы интерфейс понимал, что оплата завершена, можно сделать AJAX-endpoint:

/ajax/check_binance_payment.php

Он получает orderId, проверяет запись в Highload-блоке и возвращает текущий статус.

$order = $entityDataClass::getList([
    'filter' => [
        'UF_ORDER_ID' => $orderId
    ]
])->fetch();

echo json_encode([
    'status' => $order['UF_PAID'] ? 'paid' : 'pending'
]);

Пример ответа:

{
    "status": "paid"
}

Этот endpoint не должен сам обновлять баланс. Его задача — только показать фронтенду актуальное состояние. Обновление баланса должно происходить на сервере после webhook от Binance.

Фронтенд-проверка статуса оплаты

На фронтенде можно периодически отправлять запрос и проверять, был ли платеж обработан.

setInterval(function() {
    $.post('/ajax/check_binance_payment.php', { orderId: orderId }, function(res) {
        if (res.status === 'paid') {
            $('#modal-pay-binance').fadeOut();
        }
    });
}, 3000);

После получения статуса paid можно закрыть окно оплаты, обновить баланс в интерфейсе, показать сообщение об успешном пополнении или перезагрузить часть личного кабинета.

Если на сайте медленно обновляется личный кабинет, зависает AJAX или долго открывается платежное окно, стоит отдельно проверить фронтенд и серверную часть. В таких случаях помогает технический аудит производительности сайта.

Отображение данных в попапе оплаты

В модальном окне можно показать сумму, описание платежа, продавца и QR-код для оплаты.

<div id="modal-pay-binance">
    <p>Payment Amount: <span id="amount"></span></p>
    <p>Merchant: Device Forum LLC</p>
    <p>Details: <span id="desc"></span></p>
    <div id="qr"></div>
</div>

Данные можно заполнить из ответа Binance:

$('#amount').text(data.totalFee + ' ' + data.currency);
$('#desc').text(data.description);
$('#qr').html('<img src="' + data.qrcodeLink + '" alt="Binance Pay QR">');

Для пользователя важно, чтобы окно оплаты было понятным: какая сумма списывается, в какой валюте, что именно оплачивается и что произойдет после успешного платежа.

Ключевые требования Binance Pay

При интеграции нужно учитывать несколько технических требований:

  • merchantTradeNo — только буквы и цифры, максимум 32 символа;
  • env.terminalType — для сайта обычно используется значение WEB;
  • goodsDetails — обязательный массив с описанием товара или услуги;
  • timestamp — передается в миллисекундах;
  • signature — HMAC SHA512 в верхнем регистре;
  • data в webhook — вложенная JSON-строка, которую нужно декодировать отдельно.

Невнимательность к этим деталям обычно приводит к ошибкам создания платежа, неверной подписи, неработающему webhook или ситуации, когда пользователь оплатил, но баланс не пополнился.

Типовые ошибки при интеграции Binance Pay с Битрикс

Неправильный merchantTradeNo

Если в номере платежа есть дефисы, пробелы, подчеркивания или он длиннее 32 символов, Binance может не принять запрос. Лучше заранее сделать отдельную функцию генерации номера.

Ошибка подписи запроса

Частая причина — подписывается не тот JSON, который отправляется в API. Также нужно проверить timestamp, nonce, secret key и регистр итоговой подписи.

Webhook приходит, но баланс не обновляется

Нужно проверить, правильно ли декодируется вложенное поле data, находится ли платеж по merchantTradeNo, не стоит ли уже флаг UF_PAID, и нет ли ошибки при обновлении пользователя.

Баланс пополняется повторно

Это происходит, если не проверять, был ли платеж уже обработан. Перед начислением обязательно нужно проверять UF_PAID или другой флаг идемпотентности.

Фронтенд не закрывает окно оплаты

В этом случае нужно смотреть AJAX-проверку, формат JSON-ответа, обработку res.status и то, обновляется ли статус платежа в Highload-блоке после webhook.

Такие проблемы часто требуют не просто “поправить одну строку”, а разобраться в цепочке: создание платежа, сохранение операции, webhook, обновление баланса, AJAX и интерфейс пользователя. Это типичный пример исправления сложной PHP-логики в Битрикс.

Что проверить после внедрения

После подключения Binance Pay важно протестировать весь цикл, а не только создание QR-кода.

  1. Проверить, что платеж создается через Binance Pay v3.
  2. Убедиться, что merchantTradeNo соответствует ограничениям Binance.
  3. Проверить корректность подписи запроса.
  4. Убедиться, что запись о платеже сохраняется в Highload-блок.
  5. Проверить, что webhook приходит на сайт.
  6. Проверить декодирование вложенного поля data.
  7. Убедиться, что успешный статус PAY_SUCCESS обрабатывается корректно.
  8. Проверить, что баланс пользователя увеличивается только один раз.
  9. Проверить, что AJAX возвращает paid после оплаты.
  10. Проверить, что интерфейс личного кабинета показывает новый баланс.

Когда такая интеграция особенно полезна

Binance Pay с пополнением баланса подходит для проектов, где пользователь сначала вносит средства, а потом использует их внутри сайта.

Например:

  • личный кабинет с внутренним счетом;
  • платный форум или закрытое сообщество;
  • сервис цифровых услуг;
  • маркетплейс с внутренним балансом;
  • B2B-портал с предоплатой;
  • сайт с платными действиями или подписками;
  • система заявок, где средства списываются по мере использования.

Посмотреть похожие технические задачи по интеграциям, оплатам, личным кабинетам и нестандартной логике можно в разделе примеры работ.

Почему лучше не делать платежную интеграцию “на костылях”

В платежных сценариях любая мелкая ошибка может привести к реальной проблеме: деньги списались, а баланс не обновился; webhook пришел дважды; пользователь увидел оплату, но не получил доступ; администратор не может понять, что произошло.

Поэтому при интеграции Binance Pay важно заранее продумать:

  • структуру хранения платежей;
  • уникальные номера операций;
  • проверку подписи;
  • обработку повторных webhook;
  • логи запросов и ответов;
  • историю начислений;
  • проверку суммы и валюты;
  • поведение интерфейса после оплаты;
  • ручную проверку спорных платежей администратором.

Если проект уже работает и в нем есть старые доработки, нестандартный личный кабинет или своя система баланса, перед внедрением оплаты лучше оценить текущую архитектуру. Подробнее о подходе к таким задачам можно прочитать на странице о студии.

Итог

Интеграция Binance Pay v3 в Битрикс с пополнением баланса строится вокруг полного платежного цикла: пользователь создает пополнение, сервер формирует ордер в Binance, данные операции сохраняются в Highload-блок, webhook подтверждает оплату, после чего баланс пользователя обновляется на сайте.

Самые важные моменты: корректно сформировать merchantTradeNo, правильно подписать запрос, сохранить платеж до оплаты, обработать вложенный JSON в webhook, защититься от повторного начисления и не обновлять баланс до подтверждения PAY_SUCCESS.

Если нужно подключить Binance Pay, доработать личный кабинет, реализовать внутренний баланс, исправить webhook или разобраться, почему после оплаты не зачисляются средства, можно обратиться через страницу контактов.