Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Payment Laravel Laravel Package

professionalweb/payment-laravel

A Laravel package that simplifies online payment integration through a unified API, configurable gateways, payment requests, verification, and callback handling for adding checkout flows to Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a thin Laravel wrapper (~15 stars, last release October 2018) around professionalweb/payment, providing a Manager-style facade and driver implementations for PayOnline, Tinkoff, Yandex.Kassa, processing.kz, and upc.ua. It is a low-level, driver-based abstraction — not a full commerce solution — so expect to own the order model, routes, idempotency, and reconciliation logic yourself.

Minimal setup:

  1. composer require professionalweb/payment-laravel
  2. Register the service provider (Laravel ≤5.4 in config/app.php; 5.5+ auto-discovers) and, if you want the terse syntax, the Payment facade.
  3. Publish the config: php artisan vendor:publish --provider="ProfessionalWeb\Payment\PaymentServiceProvider" — you get a config/payment.php with a drivers block per gateway. Fill in merchant IDs, terminal keys, private/secret keys, and the success/fail/notification URLs.
  4. Pick a driver and inspect its class under ProfessionalWeb\Payment\Drivers\* (or the underlying professionalweb/payment package — most of the real logic lives there, not in the Laravel repo). That source file is your best "documentation": the interface methods are what you'll be calling.

First use case: the checkout redirect flow. Build an order, hand it to a driver to generate a payment form/URL, redirect the customer to the gateway, then handle the return (user-facing) and notification/callback (server-to-server) routes. The driver gives you the form/URL and lets you verify the callback — everything else (models, state machine, receipts) is on you.

Implementation Patterns

Resolve a driver per gateway. The facade exposes a manager, so you typically write:

use ProfessionalWeb\Payment\Facades\Payment;

$driver = Payment::driver('tinkoff'); // or 'payonline', 'yandex_kassa', ...
$form   = $driver->getPaymentForm($order); // or getPaymentUrl($order)

Wrap that call in your own PaymentGateway service/interface so controllers never depend on the string names — you'll thank yourself when a gateway is dropped or renamed.

Two-route pattern per gateway. Standard shape:

// routes/web.php
Route::post('/pay/{gateway}/notify', [PayController::class, 'notify'])->name('pay.notify');
Route::get('/pay/{gateway}/return',  [PayController::class, 'return'])->name('pay.return');
  • notify — server-to-server callback. Verify signature via the driver, look up the order using the ID the driver exposes (via getOrderId($request) or the raw payload), confirm the amount matches what you recorded, then mark the order paid. Respond with whatever body the gateway expects (often a terse string, not JSON — check the driver).
  • return — user-facing redirect after the customer finishes on the gateway. Never mark the order paid here; only show status. Real payment confirmation must come from notify.

Idempotency is mandatory. The notify route gets retried by gateways on timeout, and by support engineers. Store the gateway transaction ID on the order with a unique index; if you see the same callback twice, return success without reprocessing. Keep a raw-payload log table (gateway, order ID, body, IP, timestamp) — it makes 3am debugging possible.

Config per environment. Keep separate credential blocks and gateway URLs for sandbox vs. production in config/payment.php, and select via APP_ENV. Never put merchant private keys in a .env file you share across the team — use per-developer .env with sandbox keys.

Amount handling. Most of these gateways (Tinkoff, PayOnline, Yandex.Kassa) expect amounts in minor units (kopecks) in some APIs and major units in others. Do not trust the driver to normalise; assert in your own Order class and write a test that confirms round-tripping (create → callback → compare).

Test harness. Because the drivers are thin HTTP wrappers, you can unit-test signature verification by feeding fixture payloads from each gateway's docs into ->verify($payload). Build fixtures for at least: successful payment, failed payment, refund notification, malformed signature. That is your regression safety net given the package is unmaintained.

Integration with queues. Do your notification processing inside a queued job — the callback route should only: log, verify, dispatch, return 200. If the gateway is slow to give up, you do not want a queued retry storm hitting a synchronous handler that calls out to your DB under load.

Gotchas and Tips

  • Frozen in 2018. The package declares Laravel 5.x support; PHP 8 and Laravel 9/10 will almost certainly cause composer conflicts. If you're on a modern stack, fork it, or (better) lift the driver class you need from professionalweb/payment into your own code and depend on Guzzle directly. Treat the package as reference source, not a maintained dependency.
  • Signatures differ wildly per gateway. PayOnline uses a SecurityKey-hashed concatenation; Tinkoff uses a SHA-256 of sorted fields + secret; Yandex.Kassa uses a separate notification protocol. Do not assume you can share verification code across drivers. Read each driver's verify() and write a test per driver.
  • The verify() return value is easy to misuse. Most drivers return a boolean, but some also expose getOrderId() / getOrderAmount() that must be called after verify(). Read the driver's method order and reproduce it exactly — reversing calls silently produces zero amounts or null order IDs.
  • URL escaping of return URLs. Success/fail/callback URLs are usually embedded in the checkout request and signed. If you generate URLs with a query string, ensure they're absolute (url()->route(...) not route(...) returns relative) and URL-safe. A trailing slash mismatch will break signature checks on some gateways.
  • CSRF on the notify route. Laravel's VerifyCsrfToken middleware will 419 your callbacks. Add the notify path to $except — but only the notify path; keep CSRF on the return path if it goes through web middleware.
  • Amount unit confusion. This is the single most common production incident with these gateways. Log the amount you sent and the amount you received and compare them; don't infer.
  • Sandbox vs. production URLs are per-driver config, not a global toggle. Check config/payment.php — each driver block typically has its own url/payment_url. Copy-pasting a production block into a sandbox config is a classic mistake.
  • Extension points. All drivers implement a common interface; the manager resolves by key. To add a new gateway, implement the interface in your own package and register it in the manager (see how PaymentServiceProvider binds each driver) — no need to fork if you only need one extra provider.
  • Debugging tool. When a gateway rejects a request, log the raw outbound payload (minus secrets) and the raw inbound notification. The drivers don't always surface the gateway's own error message, so your log is often the only diagnostic.
  • No dependents means no community safety net. Search issues and the git history before assuming a method exists — several methods named in old READMEs were renamed. Let the interface file be your source of truth.
  • Upgrade path. If you're committing to more than one gateway, write your own Gateway interface with createPayment(Order): string, verify(Request): VerifiedPayment, and put the package drivers behind it. When (not if) a driver becomes stale, swapping it out is a one-class change instead of a controller refactor.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource