kodemeric / payment-gateways
A Laravel package for integrating multiple payment gateways (Paystack, Flutterwave, Monnify, and more)
Installs: 5
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/kodemeric/payment-gateways
Requires
- php: ^8.1
- illuminate/database: ^10.0|^11.0
- illuminate/http: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
- spatie/laravel-package-tools: ^1.9
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0
README
A Laravel package for integrating multiple payment gateways with a clean, extensible interface. Supports Paystack, Flutterwave, Monnify, Stripe.
Features
- ๐ Support for multiple payment gateways (Paystack, Flutterwave, Monnify, Stripe, PayPal)
- ๐ Coming soon: Pesapal, Interswitch, PayFast
- ๐ Country-agnostic - add any payment gateway from any country
- ๐ Easy to extend with new gateways (programming to an interface)
- ๐ Transaction tracking and logging
- ๐ Webhook support for all gateways
- โ Transaction verification
- ๐งช Comprehensive test coverage
Installation
composer require kodemeric/payment-gateways
Quick Install
Run the install command to set up everything at once:
php artisan payment-gateways:install
This command will:
- Publish the configuration file
- Publish the migrations
- Optionally run the migrations
Manual Installation
If you prefer to install manually:
1. Publish configuration and migrations:
php artisan payment-gateways:publish
Or publish individually:
# Publish config only php artisan vendor:publish --tag="payment-gateways-config" # Publish migrations only php artisan vendor:publish --tag="payment-gateways-migrations"
2. Run migrations:
php artisan payment-gateways:migrate
Or use the standard Laravel command:
php artisan migrate
Configuration
After publishing, configure your gateway credentials in config/payment-gateways.php:
return [ 'default_gateway' => 'paystack', 'gateways' => [ 'paystack' => [ 'test_mode' => env('PAYSTACK_TEST_MODE', true), 'public_key' => env('PAYSTACK_PUBLIC_KEY', ''), 'secret_key' => env('PAYSTACK_SECRET_KEY', ''), ], // ... other gateways ], ];
Usage
Basic Usage
use SoftPayment\PaymentGateways\Facades\PaymentGateway; // Using default gateway $gateway = PaymentGateway::default(); // Or specify a gateway $gateway = PaymentGateway::gateway('paystack');
Initiate Transaction
The package uses DTOs (Data Transfer Objects) for type safety and better structure:
use SoftPayment\PaymentGateways\Facades\PaymentGateway; use SoftPayment\PaymentGateways\Dtos\InitiateTransactionRequest; // Create request using DTO $request = InitiateTransactionRequest::fromArray([ 'amount' => 1000, // Amount in base currency 'email' => 'customer@example.com', 'reference' => 'unique_ref_123', // Optional, auto-generated if not provided 'callback_url' => 'https://yoursite.com/callback', // Optional 'user_id' => auth()->id(), // Optional, track which user initiated the transaction 'metadata' => ['order_id' => 123], // Optional ]); // Or create directly $request = new InitiateTransactionRequest( amount: 1000, email: 'customer@example.com', reference: 'unique_ref_123', callbackUrl: 'https://yoursite.com/callback', userId: auth()->id(), // Track the authenticated user metadata: ['order_id' => 123] ); $result = PaymentGateway::gateway('paystack')->initiateTransaction($request); if ($result->success) { return redirect($result->paymentUrl); }
Verify Transaction
use SoftPayment\PaymentGateways\Dtos\VerifyTransactionResponse; $result = PaymentGateway::gateway('paystack')->verifyTransaction('unique_ref_123'); if ($result->success && $result->status === 'success') { // Transaction successful $amount = $result->amount; $currency = $result->currency; }
Webhooks
Webhook routes are automatically registered:
/webhooks/paystack/webhooks/flutterwave/webhooks/monnify/webhooks/stripe/webhooks/paypal
Configure these URLs in your gateway dashboards.
Using Dependency Injection
use SoftPayment\PaymentGateways\PaymentGatewayManager; use SoftPayment\PaymentGateways\Dtos\InitiateTransactionRequest; class PaymentController extends Controller { public function __construct( protected PaymentGatewayManager $paymentManager ) {} public function pay(Request $request) { $gateway = $this->paymentManager->gateway('paystack'); $transactionRequest = InitiateTransactionRequest::fromArray([ 'amount' => $request->amount, 'email' => $request->email, 'user_id' => auth()->id(), // Track the authenticated user 'metadata' => ['order_id' => $request->order_id], ]); $result = $gateway->initiateTransaction($transactionRequest); if ($result->success) { return redirect($result->paymentUrl); } } }
Models
Transaction
use SoftPayment\PaymentGateways\Models\Transaction; $transaction = Transaction::where('reference', 'ref_123')->first(); $logs = $transaction->logs; // Get related transaction logs // Get user's transactions $userTransactions = Transaction::where('user_id', auth()->id())->get(); // Get the user who made the transaction $user = $transaction->user;
TransactionLog
use SoftPayment\PaymentGateways\Models\TransactionLog; $logs = TransactionLog::where('gateway', 'paystack')->get();
DTOs (Data Transfer Objects)
The package uses DTOs for type safety and better structure. All DTOs have fromArray() and toArray() methods for easy conversion.
InitiateTransactionRequest
The request DTO used to initiate a payment transaction with any gateway.
Properties:
amount(float, required) - The payment amount in the base currency (e.g., 1000.00)email(string, required) - Customer's email addressreference(string, optional) - Unique transaction reference. If not provided, the gateway will auto-generate onecallbackUrl(string, optional) - URL to redirect after payment completion. Defaults to config valueredirectUrl(string, optional) - Alternative redirect URL (used by some gateways)currency(string, optional) - Currency code (ISO 4217). Defaults to 'NGN'customerName(string, optional) - Customer's full namedescription(string, optional) - Transaction descriptionmetadata(array, optional) - Additional metadata to attach to the transaction (e.g.,['order_id' => 123])userId(int, optional) - ID of the user making the transaction (for tracking purposes)
Example:
use SoftPayment\PaymentGateways\Dtos\InitiateTransactionRequest; // Using fromArray (recommended) $request = InitiateTransactionRequest::fromArray([ 'amount' => 5000.00, 'email' => 'customer@example.com', 'currency' => 'NGN', 'customer_name' => 'John Doe', 'description' => 'Payment for Order #12345', 'reference' => 'ORDER_12345', 'callback_url' => route('payment.callback'), 'user_id' => auth()->id(), 'metadata' => [ 'order_id' => 12345, 'product_id' => 789, ], ]); // Using constructor $request = new InitiateTransactionRequest( amount: 5000.00, email: 'customer@example.com', currency: 'NGN', customerName: 'John Doe', description: 'Payment for Order #12345', reference: 'ORDER_12345', callbackUrl: route('payment.callback'), userId: auth()->id(), metadata: ['order_id' => 12345] );
InitiateTransactionResponse
The response DTO returned after initiating a payment transaction.
Properties:
success(bool) - Whether the transaction initiation was successfulpaymentUrl(string|null) - The payment URL to redirect the customer to (null on failure)reference(string|null) - The transaction reference (gateway-generated or the one you provided)accessCode(string|null) - Gateway-specific access code (e.g., used by Paystack)transactionReference(string|null) - Gateway's internal transaction reference (may differ from reference)message(string|null) - Error message (only present whensuccessis false)gatewayResponse(array) - Raw response data from the gateway API
Success Response Example:
$response = $gateway->initiateTransaction($request); if ($response->success) { // Redirect customer to payment page return redirect($response->paymentUrl); // Or get transaction details $reference = $response->reference; // 'ref_abc123' $accessCode = $response->accessCode; // 'ACC_xyz789' (if applicable) }
Failure Response Example:
if (!$response->success) { $errorMessage = $response->message; // 'Failed to initialize transaction' $gatewayError = $response->gatewayResponse; // Raw gateway error details }
VerifyTransactionResponse
The response DTO returned when verifying a transaction status.
Properties:
success(bool) - Whether the verification request was successfulreference(string|null) - The transaction reference that was verifiedstatus(string|null) - Transaction status: 'success', 'pending', or 'failed'amount(float|null) - The transaction amount that was paidcurrency(string|null) - The currency code (ISO 4217)message(string|null) - Error message (only present whensuccessis false)gatewayResponse(array) - Raw response data from the gateway API
Example:
use SoftPayment\PaymentGateways\Dtos\VerifyTransactionResponse; $response = $gateway->verifyTransaction('ref_abc123'); if ($response->success) { if ($response->status === 'success') { // Transaction was successful $amount = $response->amount; // 5000.00 $currency = $response->currency; // 'NGN' // Process successful payment // ... } elseif ($response->status === 'pending') { // Payment is still pending } else { // Payment failed } } else { // Verification failed (network error, invalid reference, etc.) $errorMessage = $response->message; }
WebhookPayload
The DTO that represents incoming webhook data from payment gateways. Automatically parsed from the raw request.
Properties:
data(array) - The main webhook payload data (varies by gateway)event(string|null) - Event type identifier (e.g., 'charge.success', 'charge.completed')eventType(string|null) - Alternative event type field (used by some gateways like Monnify)
Methods:
getReference()- Extracts the transaction reference from the payload, handling different gateway formats automatically
Example:
use SoftPayment\PaymentGateways\Dtos\WebhookPayload; // In your webhook handler public function handleWebhook(Request $request) { // WebhookPayload automatically parses different gateway formats $payload = WebhookPayload::fromArray($request->all()); // Get the transaction reference (works across all gateways) $reference = $payload->getReference(); // Get event type $event = $payload->event ?? $payload->eventType; // Get full payload data $data = $payload->data; }
Gateway-Specific Formats:
The WebhookPayload automatically handles different webhook formats:
- Paystack:
{ event: 'charge.success', data: {...} } - Flutterwave:
{ event: 'charge.completed', data: {...} } - Monnify:
{ eventType: 'SUCCESSFUL_TRANSACTION', eventData: {...} } - Stripe:
{ type: 'checkout.session.completed', data: { object: {...} } } - PayPal:
{ event_type: 'PAYMENT.CAPTURE.COMPLETED', resource: {...} }
WebhookResponse
The response DTO returned after processing a webhook.
Properties:
success(bool) - Whether the webhook was processed successfullyevent(string|null) - The webhook event type that was processedreference(string|null) - The transaction reference from the webhookstatus(string|null) - The transaction status after processing ('success', 'pending', 'failed')message(string|null) - Error message (only present whensuccessis false)data(array) - Additional data from the webhook processing
Example:
use SoftPayment\PaymentGateways\Dtos\WebhookPayload; use SoftPayment\PaymentGateways\Dtos\WebhookResponse; // In WebhookController (handled automatically by the package) $payload = WebhookPayload::fromArray($request->all()); $response = $gateway->handleWebhook($payload); // Response is automatically returned as JSON // Success: 200 status with response data // Failure: 400 status with error message
Success Response:
{
"success": true,
"event": "charge.success",
"reference": "ref_abc123",
"status": "success",
"data": {...}
}
Failure Response:
{
"success": false,
"message": "Unhandled webhook event",
"event": "unknown.event"
}
Artisan Commands
The package includes several helpful Artisan commands:
Install Command
Install the package (publishes config, migrations, and optionally runs migrations):
php artisan payment-gateways:install
Publish Command
Publish all package resources (config and migrations):
php artisan payment-gateways:publish
Use --force to overwrite existing files:
php artisan payment-gateways:publish --force
Migrate Command
Run the package migrations:
php artisan payment-gateways:migrate
Use --force to run in production:
php artisan payment-gateways:migrate --force
Testing
First, install dependencies:
composer install
Then run the tests:
# Run all tests composer test # or ./vendor/bin/phpunit # Run only unit tests composer test:unit # or ./vendor/bin/phpunit --testsuite=Unit # Run only feature tests composer test:feature # or ./vendor/bin/phpunit --testsuite=Feature
Requirements
- PHP 8.1+ (tested on 8.1, 8.2, 8.3)
- Laravel 10.x, 11.x, or 12.x
License
MIT