lovaszcc/laravel-barion
A Laravel integration for the Barion payment gateway, offering a simple way to handle online payments, transactions, and gateway responses within your PHP applications.
Install and publish the config:
composer require lovaszcc/laravel-barion
php artisan vendor:publish --tag=barion-config
Add credentials to .env (keys follow the published config/barion.php):
BARION_ENV=sandbox
BARION_POS_KEY=your-sandbox-poskey
[email protected]
Get a sandbox POSKey from the Barion sandbox shop admin — sandbox and production keys are entirely separate and not interchangeable.
Where to look first: the published config/barion.php (environment switch, POSKey, payee, callback/redirect URLs), then the package facade/service class, then the IPN (Instant Payment Notification) callback route if one is registered. Those three pieces define the whole integration surface.
First use case: a single-product checkout. Create a payment with an amount, currency, and PaymentRequestId (use your own order number — it is your idempotency key), store the returned PaymentId on your order row, and redirect the user to the returned GatewayUrl. Then verify the outcome server-side with a payment-state lookup rather than trusting the browser redirect.
Keep payment creation in a dedicated service, not the controller. Wrap the package call in your own BarionPaymentService that takes your Order model and returns a DTO (paymentId, gatewayUrl). This keeps the vendor API out of controllers and gives you one place to swap when the package's method signatures move.
Two-phase verification. The user returning from Barion hits your RedirectUrl, but that request proves nothing. Always call the payment-state endpoint with the stored PaymentId before marking an order paid. Treat the return URL as a UX hint ("we're confirming your payment…") and the state lookup/IPN as the source of truth.
IPN callback route. If the package exposes an IPN controller, point Barion's callback URL at it and exclude that path from CSRF in bootstrap/app.php (Laravel 11+ style) or VerifyCsrfToken. The handler should log the raw payload, look up the order by PaymentId, re-fetch state, and return 200 fast. Do the heavy work (emails, fulfilment) in a queued job.
Order state machine. Model payment states explicitly on your order (pending, paid, reserved, failed, expired) and drive transitions from the fetched state, not from the HTTP response of the create call — a successful create only means Barion accepted the request.
Environment switching via config, never hardcoded. Bind the base URL from config('barion.env') so tests and CI can force sandbox. In feature tests, fake your own BarionPaymentService interface rather than the package internals; in integration tests, use the sandbox POSKey.
Reconciliation job. A scheduled command that re-checks orders stuck in pending older than N minutes catches the dropped-callback case, which happens in production more than you'd like.
v1.0.1 "tolerates missing config" — treat this as a safety net, not a feature. The package now won't throw when config isn't published, which means a misconfigured deploy can boot cleanly and fail at payment time instead. Add a boot-time assertion or a health check that barion.pos_key is non-empty, and confirm config/barion.php is actually in your repo or CI pipeline.
Amounts. Barion expects integer amounts with the currency's minor-unit rules — HUF has no decimals. Passing 1990.00 or a float-cast value silently rounds or rejects. Store amounts as integers in the smallest unit at the boundary and convert only for display.
Payee and POSKey must belong to the same shop. A mismatch produces opaque gateway errors rather than a clear validation message.
Callback URLs need to be public. localhost and .test will never receive IPN. Use expose, ngrok, or a staging domain during development, and remember Barion's sandbox has its own callback config.
Reserved vs Succeeded. If you use the reservation flow (escrow-style), a Reserved state is not money in your account — you must explicitly finish the reservation or it lapses. If you only need simple immediate capture, configure the payment so states land on Succeeded and skip the reservation lifecycle entirely; mixing the two is the most common source of "order paid but no funds" confusion.
Laravel 13 support in this release means the package no longer pins old framework constraints, so it should install on current and older Laravel. Check your own composer.json constraint if you're on an older LTS and were previously blocked — but run your test suite against the sandbox before deploying, since the release also changed config handling.
Debugging. Log the full request/response pair at the package boundary (redact the POSKey). Barion's error payloads carry a Title/ErrorCode pair that maps far better to logs than to user-facing messages — surface a generic failure to the customer and keep the detail server-side.
Extension points. If the package binds its HTTP client or config through the container, prefer overriding those bindings over forking: swap the client in a service provider to add retries, timeouts, or request logging. Retries must be idempotent — reuse the same PaymentRequestId so a retried create doesn't produce duplicate payments.
How can I help you explore Laravel packages today?