flutterwavedev/flutterwave-v3
Laravel package for Flutterwave v3 payments, offering a simple way to initiate and verify transactions, handle payment callbacks, and integrate Flutterwave’s payment APIs into your PHP or Laravel application.
Architecture fit. flutterwavedev/flutterwave-v3 is a framework-agnostic, thin REST wrapper over Flutterwave's v3 HTTP API, distributed via Composer. It ships no Laravel service provider, no facade, no publishable config, and no DI container awareness. Architecturally it belongs at the infrastructure edge of a hexagonal/ports-and-adapters design: one adapter class implementing an internal PaymentGateway port, with the SDK never appearing in domain, controller, or job signatures. If the team lets Flutterwave::payments() calls leak into controllers and jobs, every future change (v4 migration, provider swap, test strategy) becomes a cross-cutting refactor. That constraint should be stated as a design rule in the ticket, not left to convention.
Integration feasibility. composer require plus two secrets in .env is a sub-day spike for hosted checkout (initialize → redirect → verify). Full lifecycle coverage — webhooks, refunds, transfers/payouts, subaccounts, mobile-money rails, reconciliation — is a one-to-two week body of work, most of it not SDK work at all but idempotency, reconciliation, and admin tooling. Guzzle is already a transitive dependency of laravel/framework, so dependency conflict risk is low on Laravel 10–12. Testability is the friction point: because the SDK constructs its own HTTP client, Http::fake() will not intercept it. Plan for sandbox-backed integration tests plus adapter-level fakes, and budget for sandbox flakiness in CI (keep those tests out of the blocking path).
Technical risk.
Key questions for the vendor/team.
Http calls?Stack fit. Laravel 10–12, PHP 8.2+, Guzzle 7 (already present). No service provider means manual registration in AppServiceProvider: bind a FlutterwaveGateway interface to an adapter, resolve config from config/services.php or a dedicated config/flutterwave.php, and inject the SDK client as a singleton. Keys come from the secret manager, never from a committed .env.
Migration path. If the codebase currently uses raw cURL or the community wrapper kingflamez/laravelrave, adopt a strangler pattern: define the port first, implement it against the existing integration, swap the implementation to the official SDK behind a feature flag, then delete the old path. Existing call sites should not change at all during this. If this is greenfield, skip the community wrapper — it adds a second unmaintained dependency without removing the need for our own adapter.
Compatibility. Pin an exact version ("flutterwavedev/flutterwave-v3": "x.y.z"), run composer why-not in CI against the target PHP and Laravel versions, and include one job in the matrix at the oldest supported PHP. Because a future SDK release could break on an unpinned Guzzle constraint, treat any version bump as a code-reviewed change with sandbox verification, not an automated Dependabot merge.
Sequencing.
tx_ref, queue dispatch, 200-always response policy.verify by tx_ref for any transaction stuck in pending past N minutes; this is the safety net for webhook loss, not an optional nicety.Maintenance. We own the wrapper regardless of upstream health. Budget roughly 1–2 engineer-days per quarter for dependency bumps, sandbox re-verification, and API change review — more in any quarter where Flutterwave ships a breaking change. MIT licensing gives us the fork option; decide the fork trigger now (e.g., no upstream release or issue response for 90 days) so the decision is not made under incident pressure.
Support. There is effectively no community to lean on. Support is Flutterwave's merchant channel plus our own runbook. The TPM action is to secure a named account contact and a documented escalation path before launch, and to record the incident categories that require vendor involvement (settlement discrepancies, duplicate charges, unexplained declines).
Scaling. The SDK is stateless, so application scaling is not the constraint. The constraints are provider rate limits, per-merchant throughput, and HTTP tail latency. Enforce explicit connect/read timeouts (never leave them at defaults), run all charge-initiation and reconciliation work through queues with exponential backoff and jitter, and wrap outbound calls in a circuit breaker so a Flutterwave slowdown degrades checkout gracefully instead of exhausting PHP-FPM workers.
Failure modes to design against.
tx_ref, mark it pending, and let the reconciler resolve it. This is the single largest source of duplicate-charge incidents.Ramp-up. A mid-level Laravel engineer reaches productive velocity on the hosted-checkout path in about two days given the adapter skeleton and a sandbox walkthrough; the full surface (webhooks, reconciliation, refunds, payouts) takes one to two weeks and is best paired with a written runbook. Deliverables that make this sustainable: the port interface (so mocks are trivial), a captured set of real sandbox payloads as fixtures, an on-call runbook covering the five failure modes above, and a dashboard tracking webhook lag, pending-transaction age, and gateway error rate by endpoint.
How can I help you explore Laravel packages today?