Product Decisions This Supports
- Build vs. buy for the payments layer. This package collapses what is typically 4–6 separate provider integrations (Stripe, PayPal, Flutterwave, MTN MoMo, Orange Money) into one fluent API with a shared state machine, ledger, and webhook pipeline. The decision it informs: build the checkout on top of this abstraction rather than hand-rolling per-provider clients, and treat provider choice as configuration instead of a code change.
- Market expansion sequencing. Currency-, method-, and phone-operator-based routing with built-in Cameroonian prefixes makes it cheap to test a francophone Central African market (MTN/Orange, XAF) alongside a card-first market (Stripe/PayPal). This supports decisions like "launch Cameroon with mobile money first, card second" without a separate engineering track.
- Roadmap scoping for refunds, reconciliation, and support. Full/partial refunds, automatic reconciliation of async payments, and an audit ledger are already present — these are frequently a second-phase roadmap item that PMs end up negotiating for later. Their presence lets you commit to refund self-service and finance-grade reconciliation earlier.
- Operational posture and SLAs. Failover, idempotency keys, verified and deduplicated webhooks, amount verification, and a JSON status route for polling translate directly into support decisions: what happens when MTN is down, whether a customer can be double-charged, and whether the frontend needs a "payment pending" UX rather than a blocking spinner.
- Risk/compliance decisions. The guarded state machine and audit ledger reduce the blast radius of money-moving bugs — relevant to decisions about transaction limits, manual-review thresholds, and whether you need a second approval gate for large manual refunds.
- Testing and delivery velocity as a product constraint.
Billing::fake() plus reconcile/payment/gateways/prune/mtn-sandbox-user artisan commands mean QA and staging environments can exercise real provider flows. This supports a decision to ship the payments epic inside a normal sprint cadence rather than a dedicated integration quarter.
- Explicitly out of scope, so plan for it. No subscriptions/recurring billing, no dunning, no invoicing/tax, no multi-currency ledger revaluation, and no non-African mobile money (no M-Pesa, no Airtel). If your roadmap has a recurring-revenue model, budget for a subscription layer on top or a different vendor.
When to Consider This Package
Adopt when most of these hold:
- You are on PHP 8.2+ with Laravel 11 or 12 and intend to stay on current Laravel majors — this is a hard constraint, not a preference.
- You need at least two of the supported providers concurrently, or you need Stripe and African mobile money in the same product. With a single provider and no geographic complexity, the abstraction cost likely isn't recovered.
- You are selling into Cameroon or the CEMAC/francophone-African corridor, where the built-in phone-prefix operator routing (MTN vs. Orange) is genuinely hard to replicate and a common source of misrouted-payment incidents.
- You want refunds, reconciliation, and an audit trail as day-one requirements rather than phase-two — i.e., you have a finance function that will ask "what happened to this payment" within the first month.
- You can absorb vendor concentration on a v1.0.0 package and are willing to pin the version, own the integration test coverage on your side, and accept that provider API changes may require prompt upgrades.
Look elsewhere — or plan a wrapper — when:
- You need subscriptions, metered billing, proration, dunning, or tax/invoicing. Stripe Billing, Laravel Cashier, or Paddle cover that ground; this package is a payments/checkout primitive, not a revenue platform.
- You need M-Pesa (Kenya/Tanzania), Airtel Money, or Southeast Asian wallets. Routing is Cameroon-centric.
- You are on Laravel 10 or earlier, or PHP < 8.2, or you have a policy against adopting a package at its first public release.
- You require PCI-scope minimization guarantees or SOC 2-style vendor assurance that only an established, audited provider SDK can offer. Note: Checkout/Web Payment flows keep you out of card-data scope; direct PaymentIntents may not.
- You are single-provider and single-currency — a thin client to that one provider will be simpler to debug and to explain to auditors.
- You need multi-tenant or merchant-of-record splitting, or per-tenant provider credentials with hard isolation. Verify this against the Payable/Billable traits before committing; it is not advertised.
Recommended posture: treat v1.0.0 as an evaluation-grade dependency with production potential — pilot it in one market, keep a provider-specific escape hatch, and require a written spike (one real end-to-end flow per provider, including a refund and a failed-payment reconciliation) before it becomes load-bearing.
How to Pitch It (Stakeholders)
For executives (one paragraph): We can take payments live in multiple markets — cards via Stripe and PayPal, and mobile money via MTN, Orange, and Flutterwave — through a single, consistent integration instead of five separate ones. That compresses the payments workstream and lets us enter a francophone African market with mobile-money-first checkout without a second build. Crucially, the compliance-sensitive parts (refunds, reconciliation, an audit trail, webhook verification, protection against double-charging) are built in rather than deferred, which lowers financial and reputational risk at launch. The trade-off is that this is a first release from a small package: we should pilot it in one market, pin the version, and keep a fallback, rather than bet the whole revenue path on it on day one.
For engineering (brief): Laravel 11/12, PHP 8.2+. One fluent API over Stripe (Checkout or PaymentIntents), MTN MoMo Request-to-Pay and Disbursement refunds, Orange Web Payment or Cameroon USSD push, PayPal Orders v2, and Flutterwave. Routing resolves by currency, method, and phone operator (Cameroonian prefixes built in) with optional failover. A guarded state machine enforces transitions with amount verification; webhooks are signature-verified and deduplicated; async payments self-reconcile; idempotency keys and an append-only audit ledger are first-class. Billable/Payable traits for model wiring, a JSON status route for frontend polling, Billing::fake() for tests, and artisan commands (reconcile, payment, gateways, prune, mtn-sandbox-user) for ops and sandbox setup.
What we need from engineering before committing:
- A spike per provider proving one end-to-end charge, one partial refund, and one reconciliation of a stuck async payment.
- A written review of the state machine and amount-verification logic — this is the code that protects us from money bugs.
- A confirmed answer on multi-tenant/credential isolation, if relevant to our account model.
- A pinned version plus a documented upgrade-and-rollback path, and a named owner for the dependency.
- Confirmation that polling via the JSON status route gives us an acceptable pending-payment UX, since async mobile money will not be instant.
Known gaps to state plainly: no subscriptions or recurring billing, no invoicing/tax handling, no M-Pesa/Airtel, and Laravel 11+ only. If the roadmap includes recurring revenue, budget for a separate layer — this package will not cover it.