laravel-payu maintained by beziworld
Laravel PayU
PayU REST API v2.1 for Laravel: orders, BLIK, signed notifications, capture, cancel, refunds and payment methods, with a cached OAuth token. Verified against the PayU sandbox.
Installation
composer require beziworld/laravel-payu
php artisan vendor:publish --tag=payu-config # optional
PAYU_POS_ID=300746
PAYU_SECOND_KEY=b6ca15b0d1020e8094d9b5f8d163db54 # "Second key (MD5)"
PAYU_CLIENT_ID=300746 # defaults to the POS id
PAYU_CLIENT_SECRET=2ee86a66e5d97e3fadc400c9f19b065d
PAYU_SANDBOX=true
PAYU_CONTINUE_URL=https://shop.example.com/payment/return
The values above are the public PayU sandbox POS. The notification URL defaults to the package route
/payu/notification.
Payment flow
use Beziworld\PayU\Data\OrderRequest;
use Beziworld\PayU\Data\Product;
use Beziworld\PayU\Facades\PayU;
public function pay(Request $request, Order $order): RedirectResponse
{
$created = PayU::createOrder(new OrderRequest(
totalAmount: $order->total_in_grosze,
description: "Order {$order->number}",
customerIp: $request->ip(),
products: $order->items->map(fn ($item) => new Product($item->name, $item->price_in_grosze, $item->quantity))->all(),
extOrderId: $order->number,
buyer: ['email' => $order->email, 'firstName' => $order->first_name, 'lastName' => $order->last_name, 'language' => 'pl'],
));
$order->update(['payu_order_id' => $created->orderId]);
return redirect()->away($created->redirectUri);
}
Notifications
use Beziworld\PayU\Events\OrderCompleted;
Event::listen(function (OrderCompleted $event) {
$order = Order::where('number', $event->order->extOrderId)->firstOrFail();
if (! $order->isPaid() && $event->order->totalAmount === $order->total_in_grosze) {
$order->markAsPaid(payuPaymentId: $event->paymentId);
}
});
Other events: OrderStatusChanged (every order notification) and RefundStatusChanged. The OpenPayu-Signature
header (MD5 or SHA-2) is verified over the raw body with the second key. PayU repeats notifications until it
receives HTTP 200, so listeners must be idempotent. Optionally restrict the sender with
payu.notifications.allowed_ips.
BLIK level 0
PayU::createOrder(new OrderRequest(
// ...
payMethod: ['type' => 'BLIK_AUTHORIZATION_CODE', 'value' => 'blik', 'authorizationCode' => $request->input('blik_code')],
));
Capture, cancel, refunds
PayU::order($orderId)->status; // OrderStatus::Completed
PayU::capture($orderId); // for POS without automatic capture (WAITING_FOR_CONFIRMATION)
PayU::cancel($orderId); // release the funds of an uncompleted order
PayU::refund($orderId, 'Return', 2500, "refund-{$return->id}"); // amount omitted = full refund
PayU::paymentMethods('pl'); // list<PaymentMethod> with logos and amount limits
extRefundId makes refunds idempotent: repeating the call with the same id does not refund twice.
Exceptions
ApiException (statusCode(), codeLiteral(), httpStatus(), payload()), InvalidNotification and
InvalidConfiguration, all extending PayUException.
Development
composer install
composer ci # pint --test, phpstan (level 8), pest
Author
Created and maintained by Kamil Ćwiertnia, beziworld.eu.
- E-mail: biuro@beziworld.eu
- Issues: GitHub issues
- Security vulnerabilities: see SECURITY.md
Need help integrating payments in your shop? Get in touch through beziworld.eu.
Other packages by the author
laravel-przelewy24 · laravel-tpay · laravel-paynow · laravel-autopay · laravel-inpost · laravel-company-data
License
MIT. See LICENSE.md. This package is not affiliated with PayU S.A.