starnerz/laravel-daraja
Laravel Daraja wraps all seventeen Safaricom M-Pesa Daraja APIs in ordinary Laravel code: STK Push, C2B, B2C, B2B, Dynamic QR, Ratiba, Bill Manager, typed responses, cached tokens, and testable callbacks. PHP 8.3+, Laravel 12/13.
Architecture fit. starnerz/laravel-daraja is a Laravel service-provider + facade wrapper over Safaricom's Daraja (M-Pesa) REST APIs — STK Push, C2B, B2C, transaction status, and related endpoints. It sits at the outbound integration boundary of a Laravel application and speaks JSON over Guzzle. That makes it a good fit for a monolith or modular Laravel app that needs M-Pesa without hand-rolling an HTTP client, signing, and error mapping. It is not an abstraction layer over multiple payment providers — adopting it is a deliberate commitment to Daraja's semantics (shortcodes, passkeys, callbacks, IP allowlists), which should be reflected in how the surrounding payment domain is modelled.
Integration feasibility. v5.2.0 is a permissive, non-breaking release. The requirement moves from ^7.x to ^7.8 || ^8.0, so applications already on Guzzle 8 become installable at all; applications on Guzzle 7 need no action. There are no code, config, or API changes — the only other deltas are a security contact address and a documentation domain move. For a TPM this is close to the ideal shape of a release: it removes a resolver-level blocker without changing runtime behaviour, and it is a one-line constraint bump to adopt.
Technical risk. Low but not zero, and the risk is concentrated in the Guzzle 8 claim:
Key questions.
Http facade? Is any middleware, retry, or Guzzle-specific exception handling involved?laraveldaraja.com, and what guarantees exist that the redirect from starnerz.github.io/daraja-docs/ persists?[email protected], and is there a published disclosure SLA?^7, which would make the widened constraint moot (or, conversely, is our Guzzle 8 adoption currently blocked on exactly this package)?Stack fit. Target Laravel 10/11/12 on PHP 8.3/8.4 with composer require starnerz/laravel-daraja:^5.2. The widened constraint aligns with where the ecosystem is heading: apps that have already moved to Guzzle 8 (typically because another dependency forced it) can now resolve this package instead of being deadlocked. Apps on Guzzle 7 are untouched; the resolver keeps them on 7.x.
Migration path. Effectively a no-op upgrade:
^5.2 and run composer update starnerz/laravel-daraja --with-dependencies.Compatibility checks before merge.
guzzlehttp/guzzle:^7.0 if we intend to take Guzzle 8; the package's constraint is necessary but not sufficient.Sequencing.
composer.lock until the release has been stable for a full business cycle.Adoption of Guzzle 8 itself should be a separate decision. This release makes Guzzle 8 possible, not advisable. Take the package bump now; schedule the Guzzle major separately, with its own testing, so the two changes never share a blast radius.
Maintenance. Ongoing cost is minimal. Pin the version, let Renovate/Dependabot surface future releases, and review each one — this package's release notes are unusually clear about scope, which lowers review effort. Two small housekeeping items: update internal runbooks/wiki links to laraveldaraja.com rather than relying on the redirect, and record [email protected] as the disclosure channel in our vendor registry (replacing any personal address previously noted).
Support. Support model is community/single-vendor (starnerz / EazySoft Africa) with no commercial SLA. The move to a role-based security address is a genuine improvement in governance — it survives maintainer turnover — but it is still one small team. Mitigate by keeping our integration surface thin: our own adapter around the package, config in env, and no direct dependence on package internals, so a swap to a hand-rolled client or an alternative package is a contained effort rather than a rewrite.
Scaling. The package is a thin HTTP client and holds no local state, so it does not constrain scale on its own. Throughput is bounded by Daraja's rate limits, Safaricom-side latency, and our own queueing discipline. Concurrency should be handled by queue workers with bounded retries and backoff; connection reuse matters more than the Guzzle major version. Guzzle 8 does not change our capacity profile.
Failure modes to design for (independent of this release).
Ramp-up. Low. A Laravel-fluent engineer can integrate and ship within a day; the learning curve is M-Pesa domain knowledge (shortcodes, passkeys, C2B validation vs. confirmation URLs, sandbox vs. production credentials, go-live approval), not this package. Budget onboarding time for the Daraja certification/go-live process rather than for the library.
TPM recommendation. Adopt v5.2.0 in the next routine dependency cycle. It is a widening, non-breaking change that unblocks Guzzle 8 without obliging anyone to take it. Treat Guzzle 8 migration as a separately scheduled, separately tested item; use the staging validation to confirm whether the package normalises Guzzle exceptions; and open follow-ups on the version-support policy, test strategy (sandbox vs. mocked), and the bus-factor mitigation around a single-maintainer payments dependency.
How can I help you explore Laravel packages today?