Looking to hire Laravel developers? Try LaraJobs

wayforpay-laravel maintained by aratkruglik

Description
Native Laravel integration for WayForPay payment gateway.
Author
Last update
2026/03/30 12:21 (dev-main)
License
Links
Downloads
18

Comments
comments powered by Disqus

WayForPay Laravel Package

Tests License Version

Native Laravel integration for the WayForPay payment gateway. Built on Illuminate\Http\Client with no external SDK dependencies. Provides strict DTOs, automatic HMAC_MD5 signature handling, and built-in webhook support.

Supports Laravel 11.x, 12.x and PHP 8.2+.

Table of Contents


Installation

composer require aratkruglik/wayforpay-laravel

Configuration

Publish the configuration file:

php artisan vendor:publish --tag=wayforpay-config

Add credentials to .env:

WAYFORPAY_MERCHANT_ACCOUNT=your_merchant_login
WAYFORPAY_SECRET_KEY=your_secret_key
WAYFORPAY_MERCHANT_DOMAIN=your_domain.com

Usage

1. Purchase (Widget)

Generate a self-submitting HTML form that redirects the user to the WayForPay checkout page.

use AratKruglik\WayForPay\Facades\WayForPay;
use AratKruglik\WayForPay\Domain\Transaction;
use AratKruglik\WayForPay\Domain\Product;
use AratKruglik\WayForPay\Domain\Client;

$client = new Client(
    nameFirst: 'John',
    nameLast: 'Doe',
    email: 'john@example.com',
    phone: '+380501234567'
);

$transaction = new Transaction(
    orderReference: 'ORDER_' . time(),
    amount: 100.50,
    currency: 'UAH',
    orderDate: time(),
    client: $client,
    paymentSystems: 'card;googlePay;applePay'
);

$transaction->addProduct(new Product('T-Shirt', 100.50, 1));

$html = WayForPay::purchase(
    $transaction,
    returnUrl: 'https://myshop.com/payment/success',
    serviceUrl: 'https://myshop.com/api/wayforpay/callback'
);

return response($html);

Custom Form Rendering

For SPA or custom frontend integration, use getPurchaseFormData to get raw form fields:

$formData = WayForPay::getPurchaseFormData($transaction, $returnUrl, $serviceUrl);

return response()->json([
    'form_action' => 'https://secure.wayforpay.com/pay',
    'form_data' => $formData,
]);

Submit the form programmatically on the client side:

const form = document.createElement('form');
form.method = 'POST';
form.action = data.form_action;

Object.entries(data.form_data).forEach(([key, value]) => {
    if (Array.isArray(value)) {
        value.forEach(item => {
            const input = document.createElement('input');
            input.type = 'hidden';
            input.name = `${key}[]`;
            input.value = item;
            form.appendChild(input);
        });
    } else {
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = key;
        input.value = value;
        form.appendChild(input);
    }
});

document.body.appendChild(form);
form.submit();

2. Invoices

Generate a payment link to send via email or messenger.

$response = WayForPay::createInvoice($transaction, returnUrl: 'https://myshop.com/success');
$invoiceUrl = $response['invoiceUrl'];

WayForPay::removeInvoice('ORDER_123');

3. Direct Charge (Host-to-Host)

Warning: Requires PCI DSS compliance when handling raw card data server-side.

use AratKruglik\WayForPay\Domain\Card;
use AratKruglik\WayForPay\Enums\ReasonCode;

$card = new Card(
    cardNumber: '4111111111111111',
    expMonth: '12',
    expYear: '25',
    cvv: '123',
    holderName: 'JOHN DOE'
);

$response = WayForPay::charge($transaction, $card);

$code = ReasonCode::tryFrom((int) $response['reasonCode']);
if ($code?->isSuccess()) {
    // Payment successful
}

4. Recurring Payments

Create a subscription by passing regular payment parameters during the initial purchase:

$transaction = new Transaction(
    orderReference: 'SUB_123',
    amount: 100.00,
    currency: 'UAH',
    orderDate: time(),
    regularMode: 'monthly',
    regularAmount: 100.00,
    dateNext: '25.05.2025',
    dateEnd: '25.05.2026'
);

$html = WayForPay::purchase($transaction);

Manage existing subscriptions:

WayForPay::suspendRecurring('SUB_123');
WayForPay::resumeRecurring('SUB_123');
WayForPay::removeRecurring('SUB_123');

5. Refunds

WayForPay::refund('ORDER_123', 50.00, 'UAH', 'Customer return');

6. Holds (Two-Phase Payments)

Settle a previously authorized hold:

WayForPay::settle('ORDER_123', 100.50, 'UAH');

7. P2P Credit (Payouts)

Send funds from the merchant account to a recipient card:

WayForPay::p2pCredit(
    orderReference: 'PAYOUT_001',
    amount: 500.00,
    currency: 'UAH',
    cardBeneficiary: '4111111111111111'
);

8. P2P Account Transfer

Transfer funds to a bank account (UAH only):

use AratKruglik\WayForPay\Domain\AccountTransfer;

$transfer = new AccountTransfer(
    orderReference: 'TRANSFER_001',
    amount: 1500.00,
    currency: 'UAH',
    iban: 'UA213223130000026007233566001',
    okpo: '12345678',
    accountName: 'FOP Ivanov I.I.',
    description: 'Payout for services',
    serviceUrl: 'https://myshop.com/api/wayforpay/callback',
    recipientEmail: 'recipient@example.com'
);

$response = WayForPay::p2pAccount($transfer);

9. Card Verification

Verify a card by blocking a small amount that is automatically reversed:

$url = WayForPay::verifyCard('VERIFY_ORDER_001');
return redirect($url);

10. Check Status

$status = WayForPay::checkStatus('ORDER_123');
// $status['transactionStatus']

Webhooks

The package handles signature verification automatically.

Option A: Built-in controller with event dispatching

Register the route in routes/api.php:

Route::post('wayforpay/callback', \AratKruglik\WayForPay\Http\Controllers\WebhookController::class);

Listen for the event:

use AratKruglik\WayForPay\Events\WayForPayCallbackReceived;

Event::listen(WayForPayCallbackReceived::class, function ($event) {
    $data = $event->data;

    if ($data['transactionStatus'] === 'Approved') {
        // Update order status
    }
});

Option B: Manual handling in a custom controller

use AratKruglik\WayForPay\Services\WayForPayService;
use AratKruglik\WayForPay\Exceptions\WayForPayException;

public function handle(Request $request, WayForPayService $service)
{
    try {
        $response = $service->handleWebhook($request->all());

        // Process order logic...

        return response()->json($response);
    } catch (WayForPayException $e) {
        return response()->json(['status' => 'error'], 400);
    }
}

Marketplace Integration (MMS API)

The MMS (Merchant Management System) API enables marketplace platforms to programmatically manage sub-merchants and partners, configure compensation (payout) methods, and query balances.

Available via the Mms facade or constructor injection:

use AratKruglik\WayForPay\Facades\Mms;

// Facade
Mms::addPartner($partner);

// Constructor injection
use AratKruglik\WayForPay\Contracts\MmsServiceInterface;

class PartnerController extends Controller
{
    public function __construct(
        private readonly MmsServiceInterface $mms
    ) {}
}

Partner Management

Register a new partner

use AratKruglik\WayForPay\Facades\Mms;
use AratKruglik\WayForPay\Domain\Partner;
use AratKruglik\WayForPay\Domain\CompensationCard;
use AratKruglik\WayForPay\Domain\CompensationAccount;

// Option 1: Compensation via card
$partner = new Partner(
    partnerCode: 'PARTNER_001',
    site: 'https://partner-shop.com',
    phone: '+380501234567',
    email: 'partner@example.com',
    description: 'Partner shop description',
    compensationCard: new CompensationCard(
        cardNumber: '4111111111111111',
        expMonth: '12',
        expYear: '25',
        cvv: '123',
        holderName: 'PARTNER NAME'
    )
);

// Option 2: Compensation via bank account
$partner = new Partner(
    partnerCode: 'PARTNER_002',
    site: 'https://partner-shop.com',
    phone: '+380501234567',
    email: 'partner@example.com',
    compensationAccount: new CompensationAccount(
        iban: 'UA213223130000026007233566001',
        okpo: '12345678',
        name: 'FOP Partner Name'
    )
);

// Option 3: Compensation via tokenized card
$partner = new Partner(
    partnerCode: 'PARTNER_003',
    site: 'https://partner-shop.com',
    phone: '+380501234567',
    email: 'partner@example.com',
    compensationCardToken: 'card_token_from_wayforpay'
);

$response = Mms::addPartner($partner);

Query partner info

$info = Mms::partnerInfo('PARTNER_001');

Update partner details

Mms::updatePartner('PARTNER_001', [
    'phone' => '+380509876543',
    'email' => 'new-email@example.com',
    'compensationCardToken' => 'new_token',
]);

Merchant Management

Register a sub-merchant

use AratKruglik\WayForPay\Facades\Mms;
use AratKruglik\WayForPay\Domain\Merchant;
use AratKruglik\WayForPay\Domain\CompensationCard;

$merchant = new Merchant(
    site: 'https://sub-merchant.com',
    phone: '+380501234567',
    email: 'merchant@example.com',
    description: 'Sub-merchant description',
    compensationCard: new CompensationCard(
        cardNumber: '4111111111111111'
    )
);

$response = Mms::addMerchant($merchant);

Query merchant info

Requires the sub-merchant's account ID and secret key:

$info = Mms::merchantInfo('sub_merchant_account', 'sub_merchant_secret_key');

Balance and Reporting

use AratKruglik\WayForPay\Facades\Mms;

$balance = Mms::merchantBalance();

// With date filter (dd.mm.yyyy format)
$balance = Mms::merchantBalance('01.01.2026');

Testing

vendor/bin/pest

License

The MIT License (MIT). See License File for details.