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!
- Features
- Requirements
- Installation
- Quick Start
- API Reference
- Payloads
- Error Handling
- Advanced: Custom HTTP Client
- Development
- License
- 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.
- PHP 8.1+
- A PSR-18 HTTP client (e.g.
guzzlehttp/guzzleorsymfony/http-client) - A PSR-17 factory (e.g.
nyholm/psr7)
composer require kommandhub/flutterwave-v3If 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/psr7The 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');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']);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
}$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$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']): arrayExample — 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);$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): arrayExample — 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);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 |
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
}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);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- 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.
Contributions are welcome! Please read CONTRIBUTING.md and follow the Code of Conduct.
The MIT License (MIT). See LICENSE for details.