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

v1.0.0 2025-11-21 12:11 UTC

This package is auto-updated.

Last update: 2025-12-25 11:41:05 UTC


README

A Laravel package for integrating multiple payment gateways with a clean, extensible interface. Supports Paystack, Flutterwave, Monnify, Stripe.

Tests

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 address
  • reference (string, optional) - Unique transaction reference. If not provided, the gateway will auto-generate one
  • callbackUrl (string, optional) - URL to redirect after payment completion. Defaults to config value
  • redirectUrl (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 name
  • description (string, optional) - Transaction description
  • metadata (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 successful
  • paymentUrl (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 when success is 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 successful
  • reference (string|null) - The transaction reference that was verified
  • status (string|null) - Transaction status: 'success', 'pending', or 'failed'
  • amount (float|null) - The transaction amount that was paid
  • currency (string|null) - The currency code (ISO 4217)
  • message (string|null) - Error message (only present when success is 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 successfully
  • event (string|null) - The webhook event type that was processed
  • reference (string|null) - The transaction reference from the webhook
  • status (string|null) - The transaction status after processing ('success', 'pending', 'failed')
  • message (string|null) - Error message (only present when success is 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