Інтеграція платіїної системи Robokassa на сайт
Robokassa — агрегатор платежів, що працює на російському ринку з 2003 року. Підтримує банківські карти, СБП, електронні гаманці (QIWI, ЮMoney), терміналі та рассрочку. Часто вибирають за низький поріг входу та просте підключення без тривалого узгодження.
Схема роботи
Robokassa працює за класичною redirect-схемою: сайт формує посилання з підписом та відправляє користувача на сторінку оплати Robokassa. Після оплати Robokassa сповіщає сервер (ResultURL) та перенаправляє покупця (SuccessURL/FailURL).
Параметри для підключення: MrchLogin (логін магазину), Password1 (для формування підпису в запитах), Password2 (для перевірки сповіщень від Robokassa).
Формування посилання оплати
function buildRobokassaUrl(int $orderId, float $amount, string $description): string
{
$login = env('ROBOKASSA_LOGIN');
$pass1 = env('ROBOKASSA_PASS1');
$isTest = env('ROBOKASSA_TEST', false) ? 1 : 0;
// Підпис: MD5(Login:OutSum:InvId:Password1)
$signature = md5("{$login}:{$amount}:{$orderId}:{$pass1}");
$params = http_build_query([
'MrchLogin' => $login,
'OutSum' => number_format($amount, 2, '.', ''),
'InvId' => $orderId,
'Desc' => $description,
'SignatureValue' => $signature,
'IsTest' => $isTest,
'Culture' => 'ru',
'Encoding' => 'utf-8',
'Email' => '', // email покупця, якщо відомий
]);
return 'https://auth.robokassa.ru/Merchant/Index.aspx?' . $params;
}
Якщо використовується фіскалізація, підпис включає Receipt: MD5(Login:OutSum:InvId:Receipt:Password1) — порядок важливий.
Обробка ResultURL
ResultURL — серверний коллбэк, не доступний користувачу. Саме тут відбувається смена статусу замовлення:
public function result(Request $request): Response
{
$outSum = $request->input('OutSum');
$invId = $request->input('InvId');
$received = strtolower($request->input('SignatureValue'));
// Перевіряємо підпис з Password2
$expected = strtolower(md5("{$outSum}:{$invId}:" . env('ROBOKASSA_PASS2')));
if (!hash_equals($expected, $received)) {
return response('bad sign', 400);
}
$order = Order::findOrFail($invId);
// Додатково перевіряємо суму
if (abs((float)$outSum - $order->total) > 0.01) {
return response('amount mismatch', 400);
}
$order->update(['status' => 'paid']);
// Robokassa очікує відповідь суворо в форматі "OK{InvId}"
return response("OK{$invId}");
}
Якщо Robokassa не отримує OK{InvId}, сповіщення повторюється кілька разів. Це одна з причин, чому обробник повинен бути ідемпотентним.
SuccessURL та FailURL
На SuccessURL користувач потрапляє після успішної оплати. Статус замовлення не можна змінювати тут — тільки відображати результат. Статус уже встановлений через ResultURL. Можна додатково перевірити:
public function success(Request $request): View
{
$invId = $request->input('InvId');
$outSum = $request->input('OutSum');
$received = strtolower($request->input('SignatureValue'));
$expected = strtolower(md5("{$outSum}:{$invId}:" . env('ROBOKASSA_PASS1')));
// На SuccessURL підпис лічиться з Password1, не Password2
if (!hash_equals($expected, $received)) {
abort(403);
}
$order = Order::findOrFail($invId);
return view('payment.success', compact('order'));
}
Фіскалізація
Дані чека передаються у параметрі Receipt (JSON, потім URL-encode):
$receipt = json_encode([
'sno' => 'usn_income',
'items' => [
[
'name' => 'Товар 1',
'quantity' => 1,
'sum' => 1500.00,
'tax' => 'none',
'payment_method' => 'full_payment',
'payment_object' => 'commodity',
],
],
]);
// У підпис при наявності Receipt:
// MD5(Login:OutSum:InvId:urlencode(Receipt):Password1)
$signature = md5("{$login}:{$amount}:{$orderId}:" . urlencode($receipt) . ":{$pass1}");
Тестовий режим
У тестовому режимі (IsTest=1) оплата проходит без реального списання. Карти для тестування вказані в документації Robokassa. Переключення на боевий режим — убрати IsTest та замінити ключи.
Активація нового магазину займає до 2 робочих днів. Для маркетплейсів та агрегаторів потребен окремий договір.







