heccubernny/laravel-multi-payment-gateway
Composer 安装命令:
composer require heccubernny/laravel-multi-payment-gateway
包简介
A Laravel package that acts as a multiple payment gateway API package, supporting Monnify, Stripe, Paystack, XpressPay, Upperlink, and Flutterwave.
README 文档
README
A modern, robust, and extensible Laravel package designed to handle integrations for multiple payment gateways with runtime driver switching.
Supported Gateways
- Stripe
- Paystack
- Flutterwave
- Monnify
- XpressPayments (XpressPay)
- Upperlink (Paygate)
Key Design Patterns & Features
- Manager Design Pattern: Leverages Laravel's native driver manager structure to resolve gateway drivers at runtime.
- Dynamic Gateway Switching: Easily swap gateways inline using
PaymentGateway::driver('gateway_name'). - Decoupled Architecture: Fires standard Laravel events (
PaymentSuccessful&PaymentFailed) upon transaction validation. The parent application simply listens to these events to credit or update user transactions. - Race Condition Prevention: Built-in webhook safety sleep delays ensure server-to-server notifications don't conflict with redirect callback processing.
Installation
You can install the package via Composer from Packagist:
composer require heccubernny/laravel-multi-payment-gateway
The Service Provider will be auto-discovered by Laravel. If you have auto-discovery disabled, manually register it in config/app.php (or bootstrap/providers.php on Laravel 11+):
'providers' => [ PaymentGateway\MultiPayment\PaymentGatewayServiceProvider::class, ]
Configuration
Publish the config file:
php artisan vendor:publish --provider="PaymentGateway\MultiPayment\PaymentGatewayServiceProvider" --tag="payment-gateway-config"
Configure your credentials in .env. An example .env.example file is included in the package.
Usage
1. Initialization Payloads
When initiating checkouts, different gateways require specific formats for amounts and metadata.
For Upperlink (Paygate)
- Amount: Must be in whole Naira, rounded down or to 2 decimal places.
- Metadata: Pass stringified JSON using the
metakey. - Success Check: Redirect to checkout URL on response code
"200".
use PaymentGateway\MultiPayment\Facades\PaymentGateway; $payload = [ 'amount' => floor($amountInNaira), // e.g. 5000 'merchantId' => config('payment-gateway.gateways.upperlink.ref'), 'meta' => json_encode([ 'user_id' => 1, 'payment_id' => 2, ]), 'redirectUrl' => config('payment-gateway.gateways.upperlink.redirect_url'), ]; $response = PaymentGateway::driver('upperlink')->initializeTransaction($payload); if (isset($response['code']) && $response['code'] === '200') { $checkoutUrl = $response['data']['checkOutUrl']; return redirect()->away($checkoutUrl); }
For XpressPayments (XpressPay)
- Amount: Must be in whole Naira, formatted as a string.
- Metadata: Array of name-value dictionaries.
- Success Check: Redirect to payment URL on responseCode
"00".
use PaymentGateway\MultiPayment\Facades\PaymentGateway; $payload = [ 'amount' => (string) $amountInNaira, // e.g. "5000" 'merchantId' => config('payment-gateway.gateways.xpresspay.merchant_id'), 'metaData' => [ ['name' => 'user_id', 'value' => '1'], ['name' => 'payment_id', 'value' => '2'], ], 'callbackUrl' => config('payment-gateway.gateways.xpresspay.redirect_url'), ]; $response = PaymentGateway::driver('xpresspay')->initializeTransaction($payload); if (isset($response['responseCode']) && $response['responseCode'] === '00') { $paymentUrl = $response['data']['paymentUrl']; return redirect()->away($paymentUrl); }
2. Manual Verification
You can manually verify a transaction reference using:
$reference = 'TX-123456'; // For Default Gateway $result = PaymentGateway::verifyTransaction($reference); // For Specific Gateway $result = PaymentGateway::driver('upperlink')->verifyTransaction($reference);
3. Dynamic Configuration Overrides
If your application uses dynamic database-driven credentials (e.g. multi-tenancy), you can dynamically override configuration options on the fly using the withConfig() or setConfig() methods:
use PaymentGateway\MultiPayment\Facades\PaymentGateway; $customConfig = [ 'api_key' => 'XP_SEC_LIVE_DynamicKey123', 'merchant_id' => 'XP_MERCH_DynamicId456' ]; $response = PaymentGateway::driver('xpresspay') ->withConfig($customConfig) ->initializeTransaction($payload);
You can pass any custom or optional parameters via the $payload array directly to initializeTransaction(), and the driver will forward it:
$payload = [ 'amount' => '5000', 'merchantId' => 'XP_MERCH_12345', 'currency' => 'NGN', // Optional parameter passed dynamically 'custom_channel' => 'card', // Optional parameter 'metaData' => [ ['name' => 'user_id', 'value' => '1'], ] ];
4. Exception Handling
The package handles gateway connections and configuration issues gracefully. You can intercept exceptions thrown by the package for precise error handling:
PaymentGateway\MultiPayment\Exceptions\InvalidConfigurationException: Thrown if mandatory config keys are missing.PaymentGateway\MultiPayment\Exceptions\PaymentApiException: Thrown for HTTP-level connection failures or gateway API errors (HTTP codes >= 400).
use PaymentGateway\MultiPayment\Exceptions\InvalidConfigurationException; use PaymentGateway\MultiPayment\Exceptions\PaymentApiException; try { $result = PaymentGateway::driver('xpresspay')->initializeTransaction($payload); } catch (InvalidConfigurationException $e) { // Config not set up correctly in .env Log::error("Configuration error: " . $e->getMessage()); } catch (PaymentApiException $e) { // API error (e.g., unauthorized or bad request) Log::error("Gateway error: " . $e->getMessage() . " (Code: " . $e->getCode() . ")"); }
Callbacks and Webhooks
The package includes preconfigured endpoints and controller mappings:
| Endpoint | Method | Purpose |
|---|---|---|
/api/payment/xpresspay-callback |
GET/POST |
XpressPay synchronous redirect callback |
/api/payment/upperlink-callback |
GET/POST |
Upperlink synchronous redirect callback |
/api/payment/xpresspay-webhook |
POST |
XpressPay asynchronous server-to-server webhook |
/api/payment/upperlink-webhook |
POST |
Upperlink asynchronous server-to-server webhook |
Event-Driven Local Crediting
When a webhook or callback successfully verifies a transaction, the package fires the PaymentSuccessful event. You can create a Listener in your host application to credit transactions locally.
Example Listener Setup
- Register your listener in
app/Providers/EventServiceProvider.php:
use PaymentGateway\MultiPayment\Events\PaymentSuccessful; use App\Listeners\CreditLocalPayment; protected $listen = [ PaymentSuccessful::class => [ CreditLocalPayment::class, ], ];
- Implement
App\Listeners\CreditLocalPayment.php:
namespace App\Listeners; use PaymentGateway\MultiPayment\Events\PaymentSuccessful; use App\Models\Transaction; use App\Models\User; class CreditLocalPayment { public function handle(PaymentSuccessful $event) { $gateway = $event->gateway; // e.g. 'xpresspay' or 'upperlink' $reference = $event->reference; // e.g. transaction reference string $metadata = $event->metadata; // Array containing ['user_id' => 1, 'payment_id' => 2] // Process crediting logic $userId = $metadata['user_id'] ?? null; $paymentId = $metadata['payment_id'] ?? null; $transaction = Transaction::where('reference', $reference)->first(); if ($transaction && !$transaction->isCompleted()) { $transaction->update([ 'status' => 'completed', 'gateway' => $gateway, 'metadata' => json_encode($metadata) ]); // Credit student wallet or application fee // User::find($userId)->creditWallet($transaction->amount); } } }
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-20