Интеграция платёжной системы Webpay на сайт
Webpay — белорусский платёжный шлюз, один из немногих, работающих непосредственно в Беларуси с поддержкой карт Белкарт, Visa, Mastercard и системы ЕРИП. Для белорусских интернет-магазинов и сервисов Webpay остаётся одним из основных вариантов приёма платежей.
Подключение
Договор заключается напрямую с Webpay (webpay.by). После заключения договора выдаются:
-
store_id— идентификатор магазина -
secret_key— для подписи
Тестовая среда: https://test.webpay.by
Боевая среда: https://payment.webpay.by
Инициализация платежа
Webpay работает по схеме POST-редиректа: формируется HTML-форма с параметрами и подписью, которая автосабмитится при загрузке страницы или при клике на кнопку.
function buildWebpayForm(int $orderId, float $amount, string $currency = 'BYN'): string
{
$storeId = env('WEBPAY_STORE_ID');
$secretKey = env('WEBPAY_SECRET_KEY');
$wsb_order_num = $orderId;
$wsb_total = number_format($amount, 2, '.', '');
$wsb_currency_id = $currency;
// Подпись: MD5(seed + storeId + wsb_order_num + wsb_test + wsb_currency_id + wsb_total + secretKey)
$seed = time();
$wsb_test = env('WEBPAY_TEST', 1); // 1=тест, 0=боевой
$signature = md5(
$seed .
$storeId .
$wsb_order_num .
$wsb_test .
$wsb_currency_id .
$wsb_total .
$secretKey
);
$action = $wsb_test ? 'https://test.webpay.by' : 'https://payment.webpay.by';
return <<<HTML
<form method="POST" action="{$action}" id="webpay-form">
<input type="hidden" name="*scart" value="">
<input type="hidden" name="wsb_version" value="2">
<input type="hidden" name="wsb_storeid" value="{$storeId}">
<input type="hidden" name="wsb_store" value="Магазин">
<input type="hidden" name="wsb_order_num" value="{$wsb_order_num}">
<input type="hidden" name="wsb_currency_id" value="{$wsb_currency_id}">
<input type="hidden" name="wsb_version" value="2">
<input type="hidden" name="wsb_test" value="{$wsb_test}">
<input type="hidden" name="wsb_total" value="{$wsb_total}">
<input type="hidden" name="wsb_signature" value="{$signature}">
<input type="hidden" name="wsb_seed" value="{$seed}">
<input type="hidden" name="wsb_return_url" value="https://example.com/payment/return">
<input type="hidden" name="wsb_fail_url" value="https://example.com/payment/fail">
<input type="hidden" name="wsb_notify_url" value="https://example.com/webhook/webpay">
<input type="hidden" name="wsb_lang" value="russian">
<button type="submit">Перейти к оплате</button>
</form>
HTML;
}
Уведомление об оплате (wsb_notify_url)
Webpay отправляет POST на wsb_notify_url после проведения транзакции:
public function notify(Request $request): Response
{
$data = $request->all();
// Проверка подписи
$expected = md5(
$data['wsb_seed'] .
env('WEBPAY_STORE_ID') .
$data['wsb_order_num'] .
$data['wsb_test'] .
$data['wsb_currency_id'] .
$data['wsb_total'] .
env('WEBPAY_SECRET_KEY')
);
if ($data['wsb_signature'] !== $expected) {
Log::warning('Webpay: invalid signature', $data);
return response('ERROR', 400);
}
// Проверяем код ответа банка
if ((int)$data['wsb_result_code'] === 1) { // 1 = успех
$orderId = (int)$data['wsb_order_num'];
Order::where('id', $orderId)->update([
'status' => 'paid',
'transaction_id' => $data['wsb_transaction_num'] ?? null,
]);
}
return response('OK');
}
wsb_result_code: 1 — успешная оплата, 2 — отказ, 3 — отмена покупателем.
Страница возврата
На wsb_return_url покупатель попадает после оплаты. Статус заказа уже должен быть обновлён через notify. Здесь только отображение результата:
public function return(Request $request): View
{
$orderId = $request->input('wsb_order_num');
$order = Order::findOrFail($orderId);
return view('payment.result', [
'paid' => $order->status === 'paid',
'order' => $order,
]);
}
Не полагаться на параметры в returnUrl для определения успеха — только на статус из БД, обновлённый notify-обработчиком.
Позиции заказа
Webpay поддерживает передачу позиций для детализации:
// Добавить в форму для каждой позиции:
'wsb_invoice_item_name[0]' => 'Товар 1',
'wsb_invoice_item_quantity[0]' => 1,
'wsb_invoice_item_price[0]' => '1500.00',
'wsb_invoice_item_name[1]' => 'Товар 2',
'wsb_invoice_item_quantity[1]' => 2,
'wsb_invoice_item_price[1]' => '300.00',
Тестирование
В тестовом режиме (wsb_test=1) для оплаты используются карты из документации Webpay. Переключение в боевой режим — wsb_test=0 и уведомление менеджера Webpay. Активация боевого режима занимает от 1 до 3 рабочих дней после тестирования нескольких транзакций.







