kommandhub/flutterwave-v3

A framework-agnostic PHP library for integrating Flutterwave payments using SOLID principles and PSR standards.

Maintainers

Package info

github.com/KommandHub/flutterwave-v3

pkg:composer/kommandhub/flutterwave-v3

Statistics

Installs: 12

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-22 00:03 UTC

This package is auto-updated.

Last update: 2026-03-22 02:25:20 UTC


README

Flutterwave logo

Flutterwave v3 PHP Library

A framework-agnostic PHP library for integrating Flutterwave payments using SOLID principles and PSR standards.

PHP Composer Latest Version on Packagist PHP Version License: MIT

Note: This library covers the Flutterwave features we use internally. It doesn't wrap every API endpoint yet — contributions are very welcome!

Table of Contents

Features

  • Standard Checkout — Initialize payments and redirect to Flutterwave's hosted checkout.
  • Transactions — List, verify, and view transaction timelines.
  • Transfers — Initiate transfers, check fees, and get exchange rates.
  • Refunds — Initiate and manage transaction refunds.
  • Type-Safe Payloads — Typed DTOs for consistent, validated API requests.
  • PSR-Compliant — Built on PSR-18 (HTTP Client), PSR-17 (Factories), and PSR-7 (Messages).
  • Framework Agnostic — Works in Laravel, Symfony, Slim, or plain PHP.

Requirements

Installation

composer require kommandhub/flutterwave-v3

If you don't already have a PSR-18 client and PSR-17 factories, install one alongside the library:

# Option A – Guzzle
composer require guzzlehttp/guzzle

# Option B – Symfony HTTP Client + Nyholm PSR-7
composer require symfony/http-client nyholm/psr7

Quick Start

1. Initialize the client

The library uses PSR auto-discovery — as long as a PSR-18 client and PSR-17 factories are installed, it works out of the box.

use Kommandhub\Flutterwave\Flutterwave;

$flutterwave = new Flutterwave('YOUR_SECRET_KEY');

2. Initialize a payment

use Kommandhub\Flutterwave\Payloads\CustomerPayload;
use Kommandhub\Flutterwave\Payloads\CustomizationsPayload;
use Kommandhub\Flutterwave\Payloads\PaymentPayload;

$payload = new PaymentPayload(
    amount: 1000,
    currency: 'NGN',
    tx_ref: 'unique-transaction-ref-' . time(),
    redirect_url: 'https://your-app.com/callback',
    customer: new CustomerPayload(
        email: 'user@example.com',
        phonenumber: '08012345678',
        name: 'John Doe'
    ),
    customizations: new CustomizationsPayload(
        title: 'My Store',
        logo: 'https://your-app.com/logo.png',
        description: 'Payment for order #42'
    )
);

$payment = $flutterwave->transactions()->initialize($payload);

// Redirect the user to complete payment
header('Location: ' . $payment['data']['link']);

3. Verify the payment

After Flutterwave redirects back to your redirect_url, verify the transaction using the transaction_id query parameter.

$transactionId = $_GET['transaction_id'];
$result = $flutterwave->transactions()->verify($transactionId);

if ($result['data']['status'] === 'successful') {
    // Grant the customer access / fulfill the order
}

API Reference

Transactions

$tx = $flutterwave->transactions();

// Initialize a hosted-checkout payment
$tx->initialize(PayloadInterface $payload): array

// List all transactions (supports optional filters)
$tx->all(['from' => '2024-01-01', 'to' => '2024-12-31']): array

// Verify a transaction by ID
$tx->verify(string $id): array

// Get a transaction's event timeline
$tx->timeline(string $id): array

Transfers

$tr = $flutterwave->transfers();

// Initiate a bank transfer
$tr->initiate(PayloadInterface $payload): array

// List all transfers (supports optional filters)
$tr->all(['status' => 'SUCCESSFUL']): array

// Get a single transfer by ID
$tr->get(string $id): array

// Calculate the fee for a transfer
$tr->fee(['amount' => 5000, 'currency' => 'NGN', 'type' => 'account']): array

// Get exchange rates between currencies
$tr->rates(['amount' => 100, 'source_currency' => 'USD', 'destination_currency' => 'NGN']): array

Example — initiate a bank transfer:

use Kommandhub\Flutterwave\Payloads\TransferPayload;

$payload = new TransferPayload(
    account_bank: '044',          // GTBank sort code
    account_number: '0690000031',
    amount: 5000,
    currency: 'NGN',
    narration: 'Payment for services',
    reference: 'ref-' . time(),
    callback_url: 'https://your-app.com/transfer-callback' // optional
);

$transfer = $flutterwave->transfers()->initiate($payload);

Refunds

$rf = $flutterwave->refunds();

// Initiate a refund for a transaction (partial or full)
$rf->initiate(string $transactionId, PayloadInterface $payload): array

// List all refunds (supports optional filters)
$rf->all(): array

// Get a single refund by ID
$rf->get(string $id): array

Example — partial refund:

use Kommandhub\Flutterwave\Payloads\RefundPayload;

$payload = new RefundPayload(
    amount: 500,                        // omit for full refund
    comments: 'Customer request'        // optional
);

$refund = $flutterwave->refunds()->initiate('12345678', $payload);

Payloads

All payloads extend AbstractPayload and serialize to array via ->toArray().

Payload Required Optional
PaymentPayload amount, currency, tx_ref, redirect_url, customer customizations
CustomerPayload email phonenumber, name
CustomizationsPayload title, logo, description
TransferPayload account_bank, account_number, amount, currency, narration, reference callback_url, debit_currency
RefundPayload amount, comments

Error Handling

All errors surface as FlutterwaveException. It carries the API error message, the HTTP status code, and the raw response body.

use Kommandhub\Flutterwave\Exceptions\FlutterwaveException;

try {
    $result = $flutterwave->transactions()->verify('invalid-id');
} catch (FlutterwaveException $e) {
    echo $e->getMessage();          // Human-readable error from Flutterwave
    echo $e->getCode();             // HTTP status code (e.g. 404)
    print_r($e->getResponseBody()); // Full decoded JSON body
    $e->getResponse();              // Raw PSR-7 ResponseInterface
}

Advanced: Custom HTTP Client

You can inject your own PSR-18 client and PSR-17 factories directly:

use Kommandhub\Flutterwave\Flutterwave;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Component\HttpClient\Psr18Client;

$factory = new Psr17Factory();

$flutterwave = new Flutterwave(
    secretKey: 'YOUR_SECRET_KEY',
    httpClient: new Psr18Client(),
    requestFactory: $factory,
    streamFactory: $factory
);

Or provide a fully custom implementation of HttpClientInterface (useful in tests or when wrapping another HTTP layer):

use Kommandhub\Flutterwave\Contracts\HttpClientInterface;

$flutterwave = new Flutterwave('YOUR_SECRET_KEY', client: $myCustomClient);

Development

The repository ships with a Makefile and a Docker environment.

make install   # Install Composer dependencies
make test      # Run PHPUnit test suite (--testdox)
make lint      # Run PHPStan static analysis (level 5)
make format    # Fix code style via PHP-CS-Fixer
make up        # Start Docker environment
make down      # Stop Docker environment
make shell     # Open a shell inside the app container

Running the examples locally

  1. Clone the repo and run composer install.
  2. Copy .env.example to .env and set FLUTTERWAVE_SECRET_KEY.
  3. Start the built-in PHP server:
    php -S localhost:8000 -t examples
  4. Visit http://localhost:8000.

Alternatively, use Docker (make up) — Xdebug is pre-configured for step debugging.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md and follow the Code of Conduct.

License

The MIT License (MIT). See LICENSE for details.