kommandhub / flutterwave-v3
A framework-agnostic PHP library for integrating Flutterwave payments using SOLID principles and PSR standards.
Requires
- php: >=8.1
- illuminate/support: ^10.0 || ^11.0 || ^12.0
- php-http/discovery: ^1.18
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0 || ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- mockery/mockery: ^1.6
- nyholm/psr7: ^1.5
- orchestra/testbench: ^8.0 || ^9.0 || ^10.0
- php-http/mock-client: ^1.5
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.0
- symfony/http-client: ^6.0 || ^7.0
- vlucas/phpdotenv: ^5.6
This package is auto-updated.
Last update: 2026-03-22 02:25:20 UTC
README
Flutterwave v3 PHP Library
A framework-agnostic PHP library for integrating Flutterwave payments using SOLID principles and PSR standards.
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
- Requirements
- Installation
- Quick Start
- API Reference
- Payloads
- Error Handling
- Advanced: Custom HTTP Client
- Development
- License
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
- PHP 8.1+
- A PSR-18 HTTP client (e.g.
guzzlehttp/guzzleorsymfony/http-client) - A PSR-17 factory (e.g.
nyholm/psr7)
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
- Clone the repo and run
composer install. - Copy
.env.exampleto.envand setFLUTTERWAVE_SECRET_KEY. - Start the built-in PHP server:
php -S localhost:8000 -t examples
- 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.