aratkruglik/wayforpay-laravel

Native Laravel integration for WayForPay payment gateway.

Maintainers

Package info

github.com/AratKruglik/wayforpay-laravel

pkg:composer/aratkruglik/wayforpay-laravel

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.2.0 2026-03-09 16:53 UTC

This package is auto-updated.

Last update: 2026-03-09 16:53:59 UTC


README

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.