</>
maximorum.com

Integrating LiqPay with Laravel: a complete guide for Ukrainian e-commerce

D

Integrating LiqPay with Laravel: a complete guide for Ukrainian e-commerce

Every Ukrainian online store eventually faces the same question: how do you accept payments without losing customers at checkout? LiqPay — PrivatBank's payment gateway — covers 94% of Ukrainian bank cards and processes transactions in under two seconds. Integrating it cleanly into a Laravel application takes roughly four hours of focused engineering. Here is how it works.

Laravel IDE with LiqPay payment integration code on dual monitors in a navy office

Why LiqPay and why Laravel

LiqPay supports Visa, Mastercard, Prostir, and Apple Pay. It handles recurring billing, one-click payments, and holds/captures — essential for stores with complex fulfilment workflows. Laravel, with its service container and queue infrastructure, is the right host for payment logic: testable, maintainable, and easy to extend.

The integration flow

LiqPay uses a two-field form submission model. You encode a data payload (Base64 JSON) and sign it with a SHA1 hash of your private key. Your Laravel controller generates both fields, renders a checkout form, and handles the server callback when PrivatBank confirms the transaction.

// LiqPayService.php
public function generatePaymentData(Order $order): array
{
    $data = base64_encode(json_encode([
        'version'     => 3,
        'public_key'  => config('liqpay.public_key'),
        'action'      => 'pay',
        'amount'      => $order->total,
        'currency'    => 'UAH',
        'description' => "Order #{$order->id}",
        'order_id'    => $order->uuid,
        'result_url'  => route('checkout.success'),
        'server_url'  => route('liqpay.callback'),
    ]));

    $signature = base64_encode(sha1(
        config('liqpay.private_key') . $data . config('liqpay.private_key'),
        true
    ));

    return compact('data', 'signature');
}

Handling the server callback

LiqPay sends a POST to your server_url with a data and signature field. You verify the signature before touching the database. If it matches and status is success, you dispatch a PaymentConfirmed event and update the order.

// LiqPayController.php
public function callback(Request $request): Response
{
    $data      = $request->input('data');
    $signature = $request->input('signature');

    if (! $this->liqPay->verifySignature($data, $signature)) {
        abort(403, 'Invalid signature');
    }

    $payload = json_decode(base64_decode($data), true);

    if ($payload['status'] === 'success') {
        PaymentConfirmed::dispatch($payload['order_id']);
    }

    return response('OK');
}

Queue the side effects

Never run email, PDF generation, or warehouse API calls inside the callback controller. Dispatch them as queued jobs. If PrivatBank retries the callback — and it does, up to three times — your idempotency check on order_uuid prevents double-processing.

Testing before go-live

LiqPay provides a sandbox mode: set action to pay and use test card 4242 4242 4242 4242. Run your full checkout flow against the sandbox, verify callbacks fire correctly, and check that your event listeners log the right outcomes.

What this delivers for your business

A clean LiqPay–Laravel integration means fewer abandoned carts, no manual payment confirmations, and a checkout that handles peak load without drama. Most clients see a 15–20% drop in checkout abandonment within the first month after switching from manual bank transfers to automated LiqPay flows.

Ready to add reliable Ukrainian payment processing to your Laravel application? MaxiMoruM has integrated LiqPay into dozens of production systems. Contact us at maximorum.com and we will scope the work in a 30-minute call.

Maximus AI
Online
Привіт! Я ваш AI-асистент. Чим можу допомогти з вашим проектом?