Интеграция системы ЕРИП на сайт

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Интеграция системы ЕРИП на сайт
Сложная
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Интеграция системы ЕРИП на сайт

ЕРИП (Единое расчётное и информационное пространство) — государственная платёжная система Беларуси. Позволяет принимать платежи через интернет-банкинг, банкоматы, платёжные терминалы, мобильные приложения банков. Охват — более 99% белорусских банков и платёжных терминалов. Для большинства белорусских сервисов интеграция ЕРИП обязательна: значительная часть пользователей предпочитает платить именно через ЕРИП, особенно через СДБО Сбербанка и Беларусбанка.

Архитектура ЕРИП

Есть два пути подключения:

  1. Через банк-агент — банк (Беларусбанк, Приорбанк, БСБ Банк и др.) предоставляет шлюз к ЕРИП. Договор с одним банком, API банка.
  2. Напрямую через ОСМП/ФТОС — требует отдельного договора с оператором ЕРИП, более сложная инфраструктура.

Для большинства проектов выбирается путь через банк-агент. Рассмотрим интеграцию через наиболее распространённый вариант — БСБ Банк (API WSCP) и Беларусбанк (webservice).

Концепция работы

ЕРИП работает в режиме Pull: это не редирект-схема. Покупатель вводит ваш номер услуги в ЕРИП (например, «Интернет-магазины → ВашМагазин → Введите номер заказа»). ЕРИП запрашивает у вашего сервера информацию о заказе (Check-запрос), затем после оплаты отправляет уведомление (Pay-запрос).

Ваш сервер должен реализовать обработчик XML-запросов от ЕРИП.

Реализация обработчика

class EripController extends Controller
{
    public function handle(Request $request): Response
    {
        $xml = simplexml_load_string($request->getContent());
        $command = (string)$xml->command['type'];

        return match ($command) {
            'check' => $this->check($xml),
            'pay'   => $this->pay($xml),
            default => $this->error('Unknown command'),
        };
    }

    private function check(\SimpleXMLElement $xml): Response
    {
        $accountNo = (string)$xml->customer->account;
        $order = Order::where('erip_account', $accountNo)
            ->where('status', 'pending')
            ->first();

        if (!$order) {
            return $this->xmlResponse(200, 'Услуга не найдена');
        }

        $responseXml = <<<XML
        <?xml version="1.0" encoding="UTF-8"?>
        <response>
            <result>
                <errorCode>0</errorCode>
                <errorDescription>Успешно</errorDescription>
            </result>
            <customer>
                <account>{$accountNo}</account>
            </customer>
            <fields>
                <field tag="250" tagName="Сумма к оплате" value="{$order->total}"/>
                <field tag="251" tagName="Номер заказа" value="{$order->id}"/>
            </fields>
            <amount>{$order->total}</amount>
            <currency>933</currency>
            <info>Заказ #{$order->id} от {$order->created_at->format('d.m.Y')}</info>
        </response>
        XML;

        return response($responseXml, 200)
            ->header('Content-Type', 'application/xml; charset=utf-8');
    }

    private function pay(\SimpleXMLElement $xml): Response
    {
        $accountNo   = (string)$xml->customer->account;
        $transId     = (string)$xml->transaction['id'];
        $amount      = (float)$xml->transaction->amount;
        $paymentDate = (string)$xml->transaction['date'];

        $order = Order::where('erip_account', $accountNo)
            ->where('status', 'pending')
            ->lockForUpdate()
            ->first();

        if (!$order) {
            return $this->xmlResponse(100, 'Счёт не найден');
        }

        if (abs($amount - $order->total) > 0.01) {
            return $this->xmlResponse(200, 'Неверная сумма');
        }

        // Идемпотентность — не обрабатывать повторно
        if (EripTransaction::where('transaction_id', $transId)->exists()) {
            return $this->xmlResponse(0, 'Уже обработан');
        }

        DB::transaction(function () use ($order, $transId, $amount, $paymentDate) {
            EripTransaction::create([
                'transaction_id' => $transId,
                'order_id'       => $order->id,
                'amount'         => $amount,
                'paid_at'        => $paymentDate,
            ]);
            $order->update(['status' => 'paid']);
        });

        return $this->xmlResponse(0, 'Принято');
    }

    private function xmlResponse(int $code, string $message): Response
    {
        $xml = <<<XML
        <?xml version="1.0" encoding="UTF-8"?>
        <response>
            <result>
                <errorCode>{$code}</errorCode>
                <errorDescription>{$message}</errorDescription>
            </result>
        </response>
        XML;

        return response($xml, 200)
            ->header('Content-Type', 'application/xml; charset=utf-8');
    }
}

Номер лицевого счёта ЕРИП

Каждому заказу присваивается уникальный номер лицевого счёта. Обычно это сам ID заказа, но некоторые банки требуют определённого формата (например, 15-значный номер). Этот номер отображается покупателю и вводится в терминале ЕРИП.

Номер счёта нужно сгенерировать заранее и показать покупателю на странице оформления:

// Генерация номера ЕРИП-счёта
$order->erip_account = str_pad($order->id, 12, '0', STR_PAD_LEFT);

QR-код для ЕРИП

Для упрощения оплаты через мобильные приложения можно генерировать QR-код с данными ЕРИП. Формат QR определяется банком-агентом; обычно это глубокая ссылка вида:

erip://pay?service_code=XXXXX&account=000000012345
use Endroid\QrCode\QrCode;

$qrCode = QrCode::create("erip://pay?service_code={$serviceCode}&account={$order->erip_account}")
    ->setSize(200);

Настройка в дереве услуг ЕРИП

Ваш сервис должен быть зарегистрирован в дереве услуг ЕРИП — это делается через банк-агент. Процедура включает: заполнение заявки, согласование места в дереве (например, «Интернет-магазины → [Регион] → Название магазина»), тестирование. Срок регистрации и тестирования — от 5 до 15 рабочих дней. Изменение позиции в дереве после регистрации — отдельная заявка и ещё 5–10 дней.

Безопасность

Запросы от ЕРИП нужно принимать только с IP-адресов банка-агента. Список IP предоставляет банк. Дополнительно — HTTPS с взаимной аутентификацией (mutual TLS) или HMAC-подпись в зависимости от банка.

// Middleware для проверки IP
public function handle(Request $request, Closure $next): Response
{
    $allowedIps = explode(',', env('ERIP_ALLOWED_IPS'));
    if (!in_array($request->ip(), $allowedIps)) {
        return response('Forbidden', 403);
    }
    return $next($request);
}