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

Laravel Payment Laravel Package

overtrue/laravel-payment

A Laravel payment integration package that provides a unified API for Alipay and WeChat Pay. It simplifies configuring credentials, creating payments, handling callbacks, and supporting common scenarios like web, app, and QR payments—ideal for adding Chinese payment gateways to Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

This release (4.0.0) is a compatibility refresh, not a feature release. The day-to-day API is unchanged, but the platform floor moved: PHP ^8.3 and Laravel ^13.30 only. If you are on Laravel 12 or PHP 8.2, stay on 3.x until you upgrade.

  1. Upgrade in the right order. PHP 8.3+ → Laravel 13.30+ → overtrue/laravel-payment:^4.0 → gateway drivers. The package now requires league/omnipay ^3.2.1 and omnipay/common ^3.5.1, so any separately installed driver must be compatible with those. Check with composer why-not league/omnipay 3.2.1 and by running your own gateway tests, not just composer update.
  2. Publish and read the config first. The published config/payment.php is the map of the package: default gateway, gateways.*.driver, and gateways.*.options. Most day-to-day confusion is a config/env mismatch, not code.
  3. First use case: take a payment with the default gateway.
use Overtrue\LaravelPayment\Facades\Payment;

$response = Payment::gateway('alipay')->purchase([
    'out_trade_no' => $order->number,
    'total_amount' => $order->total,
    'subject'      => $order->description,
    'notify_url'   => route('payments.notify', ['gateway' => 'alipay']),
    'return_url'   => route('payments.return'),
]);

return $response->isRedirect()
    ? redirect($response->getRedirectUrl())
    : back()->withErrors($response->getMessage());

The returned object is an Omnipay response. The methods you will use daily are isRedirect(), getRedirectUrl(), isSuccessful(), getTransactionReference(), and getMessage().

  1. Then wire the asynchronous callback. The redirect is UX; the notify endpoint is the source of truth. In the callback, call completePurchase() on the same gateway with the incoming request data, verify the result, then fulfil the order idempotently.

Implementation Patterns

Explicit gateway per transaction. Use Payment::gateway() with no argument for the configured default, and an explicit name when the choice is business-driven (currency, region, tenant, payment method). Because gateway names remain nullable, passing null deliberately falls back to the default — make that decision explicit in your code instead of letting a null tenant setting silently route traffic.

$gateway = Payment::gateway($order->payment_method); // 'alipay', 'wechat', ...

Config-driven multi-gateway setup. Keep credentials in config/payment.php reading from env, one entry per gateway name. This lets you add a gateway without touching application code and lets ops switch the default per environment. Run php artisan config:cache as part of deploy and remember cached config ignores later .env edits.

Callback verification pattern. A robust notify handler looks like:

public function notify(Request $request, string $gateway)
{
    $response = Payment::gateway($gateway)->completePurchase($request->all());

    abort_unless($response->isSuccessful(), 400, $response->getMessage());

    // Verify amount, currency and out_trade_no against your order before fulfilling.
    // Enforce a unique constraint on (gateway, transaction_reference) for idempotency.
}

Do the same in the return handler, but treat it as display-only: it can be spoofed or abandoned. Fulfilment belongs in the notify path.

Refunds and queries reuse the same gateway. Payment::gateway('alipay')->refund([...]) and ->query([...]) follow the purchase shape. Pass the original out_trade_no and your own out_refund_no; persist both so retries are idempotent.

Gateway caching and state. Gateway instances are cached, and 4.0 explicitly preserves that behaviour. Treat the instance as shared and stateless: pass all per-transaction parameters to each purchase() / refund() call rather than mutating the gateway with setters. If a driver requires per-request configuration, resolve a distinct configured gateway name rather than mutating the cached one.

Custom gateways. If you maintain an in-house Omnipay driver, point the config driver at your class (or register it through the package's extension point if your version exposes one) and cover it with your own integration test. The release notes confirm the factory implementation is unchanged, so existing custom drivers should continue to resolve — the risk is their Omnipay dependency constraints, not the factory.

Testing. Swap the facade root or bind a fake gateway in the container; the package's own suite uses a dummy gateway and makes no live calls. Assert the outgoing parameter array (order number, amount, notify URL) and drive callback tests with captured fixture payloads from each provider. Add one test that resolves every configured gateway so a bad driver or missing credential fails CI, not production.

Gotchas and Tips

  • This is a hard platform break. Laravel 13.30 is a specific minimum, not just "Laravel 13". A stale composer.lock on 13.29 will fail resolution. Upgrade Laravel first, then the package.
  • Drivers are the real upgrade risk. The package only wraps Omnipay; the gateway driver is a separate package. Omnipay Common 3.5.1 and Omnipay 3.2.1 change signatures that older drivers may rely on. Run a real sandbox purchase, callback, refund and query for each driver after upgrading — a green composer update proves nothing about signature compatibility.
  • Array option expansion is preserved and is a trap. Array options expand into individual setter arguments. If you actually need to pass a single array as one argument, wrap it in an outer array. This bites when a driver setter expects an array (for example a list of options) and you pass it bare — it gets splatted instead of assigned. Test option-heavy gateways explicitly after the upgrade.
  • Nullable gateway names are intentional. Payment::gateway(null) resolves the default. This is convenient and dangerous: a null column from the database will silently route to the default gateway. Validate the payment method before it reaches the factory.
  • Don't suppress the deprecation noise. The release notes call out that oldest-allowed transitive dependencies can emit deprecations on PHP 8.4+. That is an upgrade signal, not a bug in your app. Update dependencies rather than adding error_reporting masks, and run CI on both lowest and latest dependency sets.
  • Debugging gateway failures. Most exceptions are Omnipay's InvalidRequestException for missing or malformed parameters, or driver-level signature errors. Log the outgoing parameter array and the response body with secrets redacted; never log private keys, API secrets or full callback payloads containing customer data.
  • Callback payload handling. Signature checks depend on the exact raw fields the provider sent. Don't rebuild the payload from your own model, don't reformat amounts or timestamps, and be careful with JSON versus form-encoded notify bodies — Omnipay drivers expect the provider's field names, not your domain names.
  • Idempotency is your job. Providers retry notifications. Enforce a unique index on the provider transaction reference and make fulfilment transactional; isSuccessful() alone does not make a handler safe to run twice.
  • Config cache and env. After changing gateway credentials, php artisan config:clear locally and redeploy with config:cache. A cached config with old keys is the most common "it works locally" failure for this package.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource