Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Daraja Laravel Package

savannabits/daraja

Laravel package for Safaricom's M-Pesa Daraja API, simplifying STK Push, C2B, B2C, transaction status and reversal requests with fluent, configurable methods so you can integrate mobile payments into your PHP app quickly.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a thin HTTP convenience wrapper, not a payments subsystem. What it actually buys you is (a) fluent Laravel-style method calls over raw Daraja payloads, (b) automatic OAuth token acquisition and caching, and (c) a publishable config file so credentials live in .env. Everything that makes a money path safe — idempotency, transaction state machine, callback authenticity, reconciliation, multi-tenant shortcode routing — is not in the package and lands on our team regardless of whether we adopt it. That reframes the decision: we are not evaluating a platform, we are evaluating whether to borrow roughly a few hundred lines of OAuth and request-shaping code. The architectural fit is therefore good only if we place it behind our own PaymentGateway interface and never let Daraja:: appear in a controller, job, or Livewire component. With that boundary, the package is swappable in a one-class diff; without it, it becomes an untested vendor coupling on the revenue path.

Integration feasibility. High for the code, low for the calendar. Engineering is realistically 1–3 days for the first end-to-end sandbox STK Push (persist row → request → callback handler → status query), plus ~1 day to read src/ end-to-end and enumerate the public surface. The real critical path is non-engineering: shortcode provisioning, Daraja portal app registration, callback URL registration, and Safaricom go-live approval. That is measured in weeks, and it must start the same week as the spike, not after it. Any plan that sequences "build it, then apply for go-live" is a plan that ships late. Secondary feasibility question: declared support is PHP 8.1 / Laravel 9 (released Nov 2022). If our target is Laravel 10/11/12, "it probably works" is not a support statement and must be verified rather than assumed.

Technical risk. Ranked:

Risk Severity Notes / mitigation
Unauthenticated callbacks enabling forged credits Critical Daraja callbacks have no signature scheme. Handler must trust only CheckoutRequestID and read amount from our DB. Requires security sign-off before production.
Lost outbound response → charged customer, no record Critical Mandatory indeterminate state + reconciliation sweep. Non-negotiable.
Duplicate / out-of-order callbacks double-crediting High Unique index on checkout_request_id, lockForUpdate, absorbing terminal states, 200 OK to duplicates.
ResultCode 1037 (timeout) silently charges High Treat unknown codes as indeterminate → poll, never as failed. Taxonomy mapped to our own enum.
Unverified v1.0.0 rewrite (0.2.0 → 1.0.0, single PR, no migration guide) Medium Diff PR #1, pin exactly 1.0.0 (not ^1.0), commit the published config.
Maintenance abandonment: 1 maintainer, 12 stars, 0 dependents, no release since Nov 2022 Medium Acceptable only because fork cost is low. Pre-approve a fork budget and name an owner.
Multi-tenancy retrofit Medium Cheapest to verify now, most expensive to add later — resolve before the data model is committed.

Key questions (need answers before we commit).

  1. Single shortcode or per-merchant/per-branch? Determines whether the package's config model is sufficient or we need scoped container bindings and per-tenant token cache keys.
  2. What is our actual Laravel/PHP target, and does the package's guzzlehttp/guzzle constraint reconcile with our lockfile? If Laravel 8/PHP 8.0, adoption implies a framework upgrade — that's a roadmap dependency, not a sprint surprise.
  3. Is the client bound as a singleton with fixed config? That governs runtime config override for multi-tenant work.
  4. What do the methods actually return — arrays, DTOs, or Illuminate\Http\Client\Response? Anything but our own DTOs means coupling to Safaricom JSON field names.
  5. Who owns the Safaricom relationship and the go-live paperwork, and what is the stated approval lead time?
  6. Does a refund/reversal credential set (initiator name + password) exist today, or is it a future provisioning task we're about to discover mid-incident?

Integration Approach

Stack fit. Good for a Laravel 9+ app that wants M-Pesa as one payment rail among several. The facade + config + token caching model is idiomatic and low-ceremony, which is genuinely the package's value proposition. It is a poor fit for anything unusual: multi-tenant marketplaces, per-request credential rotation, or non-Laravel services. If M-Pesa is the primary revenue rail with high volume and strict SLA, the thin wrapper stops paying for itself and we should expect to fork.

Migration path. There is nothing to migrate from if we're greenfield on M-Pesa. If we have existing raw-cURL Daraja code, treat migration as opportunistic: introduce PaymentGateway, implement it via the package, and port flows one at a time (STK Push → status query → C2B → B2C → reversal). Do not attempt a big-bang port of reversal/refund before the reversal credentials exist — that path is separately provisioned and routinely forgotten until the first refund is needed.

Compatibility. Pin savannabits/daraja:1.0.0 exactly, commit config/daraja.php into the repo rather than relying on package defaults, and record the verified Laravel/PHP/guzzle matrix somewhere durable (README + CI job). Add contract tests that replay recorded sandbox request/response fixtures through Http::fake() — this is the specific artifact that catches vendor payload drift on any future package bump and is what protects us during a fork.

Sequencing (with exit criteria).

  1. Week 1 — Spike + paperwork in parallel. Install, publish config, read src/, stand up ngrok/expose callback, complete one sandbox STK Push, and log a full real callback body. In parallel: submit shortcode and go-live documentation. Exit: a persisted row carries a CheckoutRequestID before the request is sent, and the callback handler finds it.
  2. Week 2 — Harden. PaymentGateway interface + MpesaPaymentService; state machine with row locks; queued outbound calls with bounded concurrency, timeout, 3 tries, backoff; 401 → flush cache and retry exactly once.
  3. Week 3 — Ops surface. Scheduled reconciliation (5–15 min: sweep pending > 90s and all indeterminate; escalate > 24h to manual review with alerting). Sandbox-test reversal on day three of adoption, not month three of production.
  4. Week 4 — Security + observability review. Callback route hardening (IP allowlist, CSRF exception, no auth middleware, no amount from body), DTO normalisation at the service boundary, runbook drafted.
  5. Gate — go-live. Blocked on Safaricom approval. No production traffic until the security review and a sandbox smoke test both pass.

Operational Impact

Maintenance. The package itself is low-maintenance because it is small and we should expect to own it. Single maintainer, no release since Nov 2022, zero dependents. The honest position: we are adopting a pinned snapshot, not a supported dependency. Name an internal owner, watch the upstream repo, and pre-approve a fork budget — the surface is small enough that forking is cheap, and a fork removes the dependency risk entirely. The expensive maintenance is not the package; it is our own state machine, reconciliation job, and result-code taxonomy.

Support. Two distinct support burdens. First, engineering: a reconciliation job, alerting, and a status-query path that must be treated as the source of truth (the callback is only a fast path). Second, ops/business: a manual-review queue for transactions escalated past ~24h, plus a runbook covering the two-phase STK flow, result-code meanings, callback retry behaviour, portal registration steps, and the go-live checklist. Write this in our repo, not by pointing at the package README — the knowledge is ours to own and the package will not supply it. Budget real headcount for the review queue; it is not a set-and-forget job.

Scaling. Three constraints, in order of when they'll bite. (1) Per-shortcode throttling — M-Pesa rate-limits per shortcode, so outbound calls need a dedicated queue connection with bounded concurrency and a RateLimiter/circuit breaker so a Safaricom incident doesn't cascade into queue depth for unrelated work. (2) Synchronous calls in web requests — never; 30-second page loads during Safaricom incidents are the predictable outcome. (3) Multi-tenancy — if the client is a singleton with fixed config, per-merchant scaling requires one worker pool per shortcode plus runtime config([...]) scoped bindings, and per-instance token caching risks cache-key collisions across tenants. Verify before the data model lands; retrofitting this is the single most expensive thing on the list.

Failure modes. Define these up front and design the runbook around them: indeterminate (request may have succeeded, response lost — a real state, swept by reconciliation, never auto-failed); duplicate/out-of-order callbacks (normal, absorbed with 200 OK); 1037 timeout (may have charged — always poll); OAuth 401 on a business request (cached-but-revoked token — flush and retry once, never loop); cache store flushed in a deploy script (token hammering → rate limit — exclude the package's store from cache:clear and health-check it); Safaricom outage (circuit breaker open, queue drains on recovery, reconciliation catches the tail). The unifying rule: unknown is not failed — anything unrecognised routes to status query, and terminal states are absorbing.

Ramp-up. For a competent Laravel engineer: ~1 hour to read src/ end-to-end, ~1 day to a working sandbox STK Push, ~1 week to a hardened implementation with a state machine and queue. The package is small enough that reading it is a prerequisite, not an option — and it is on a money path, so "I skimmed the README" isn't acceptable. Do not gate CI on the sandbox: it is flaky enough that a manually-triggered smoke test is the right cadence. Total realistic ramp for the team including security review and runbook: 3–4 weeks of engineering-adjacent effort, with the launch date set by Safaricom's approval clock rather than ours.

Recommendation. Adopt for a pilot or a secondary payment rail, behind our own PaymentGateway interface, pinned to 1.0.0 with committed config, with a named owner and a pre-approved fork budget. Do not adopt it as a payments platform, and do not start the shortcode paperwork after the spike — start it the same week.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast