masihjay-z/kavenegar
Laravel integration for the Kavenegar SMS API, providing a simple way to send SMS messages, OTP codes, and lookup-based notifications from your PHP applications through a clean, framework-friendly wrapper.
Architecture fit. This is a narrow point solution: a Laravel 4/5 service provider and facade wrapping Kavenegar's SMS REST API, with config publishing, verification-code/lookup helpers, and multi-recipient sending. It fits exactly one architecture — a legacy Laravel 4/5 monolith that has already committed to Kavenegar as its SMS gateway and needs a fast path to "send a text." It does not fit anything resembling a target-state architecture: no multi-provider abstraction, no Notification channel contract, no queue integration, no delivery-receipt or inbound-webhook surface, no idempotency. As a TPM, treat the package as a tactical accelerant inside an already-frozen stack, not as a component you architect around. The strategic asset here is the product question it unlocks (does SMS/OTP ship for our Iran-facing users, and with which vendor), not the code.
Integration feasibility. Mechanically trivial: composer require, manual provider/alias registration (it predates 5.5 auto-discovery), vendor:publish, API key and sender line in env, then facade calls. The killer is not effort — it's the adoption signal. Zero stars, zero dependents, score 0, no release cadence, no CI/test evidence, no named maintainer. Feasibility for a TPM is therefore not "can we install it" but "can we defend it in a design review." The answer is no for new work. Compare the ~2–5 engineering days to write an in-house Kavenegar client (retries, throttling, structured logging, a SmsSender interface) against the ~1–2 days saved by adopting this — that delta is the entire business case, and it's negative the moment one production incident requires reading undocumented source.
Technical risk. High, and concentrated in ways that are cheap to avoid now and expensive to unwind later:
send vs. Send vs. sendSms), config keys, and whether the facade returns the provider's response body or a collapsed boolean. A boolean return is the worst outcome: it destroys error diagnosability for OTP, where silent failure is a user-facing login outage.return.status 400+, Persian return.message) for bad keys, exhausted credit, blacklisted numbers, and invalid sender lines. Any wrapper that treats "no exception" as success will report healthy while messages fail.Key questions.
illuminate/support and PHP constraints in composer.json?kavenegar/laravel or Kavenegar's own PHP SDK — that clears a basic due-diligence bar?Stack fit. Acceptable only for a legacy Laravel 4/5 codebase already on Kavenegar. For Laravel 6+, and categorically for 9/10/11, do not adopt: use Laravel's Http client or the official SDK behind a first-party adapter. The TPM's framing to stakeholders should be "this package is scoped to a stack we are leaving," which reframes the conversation from package selection to upgrade sequencing.
Migration path. Never let the facade leak into controllers or domain code. Sequence:
SmsSender interface (send, optional sender line, structured result object with provider status code and message).KavenegarSender behind that interface, delegating to the package initially if it must ship now.If the package must remain temporarily, pin the exact version — or vendor/fork it — so an upstream deletion cannot break the build.
Compatibility. Assume PHP 5.x/7.x-era constraints, Laravel 4/5 provider and facade conventions, and an older Guzzle. Modern PHP 8, strict typing, package auto-discovery, and current Guzzle are likely incompatible or untested. Verify in a throwaway branch before committing to any plan that depends on it; do not let a spike in a legacy container become an implicit production commitment.
Sequencing. Time-boxed spike first (half a day against Kavenegar test credentials: confirm send, status, error codes, per-second rate limits, and multi-part billing behaviour for Persian text). In parallel — not after — run the vendor/compliance screen, because a red light there makes the technical work moot. Then build the adapter and a queued send path, add observability and credential management, shadow-test in staging with a logging sender, and cut over. Front-load the vendor decision; back-load the code.
Maintenance. Treat the package as abandoned on arrival. There is no credible upstream signal — no release cadence, no test suite, no issue triage. The obligation you inherit is fork-and-own. The consolation is that the owned surface is genuinely small: the underlying integration is a handful of REST calls, so replacing it with first-party code is days, not weeks. Budget that replacement explicitly rather than pretending the dependency is free.
Support. No vendor SLA, no community, no escalation path. Kavenegar may support its API, but nobody supports this wrapper — the source code is the runbook, and your engineers are the second line. That is acceptable for a stopgap with a removal date; it is not acceptable for an OTP path that gates user login.
Scaling. Throughput is bounded by the Kavenegar account (per-second caps, credit balance), not by the package — so "will this scale" is the wrong question. The right one is whether your send path scales: the package almost certainly performs synchronous blocking HTTP calls inline, which means request latency, worker exhaustion, and cascade failures under load. Production requires queuing, throttling (Redis::throttle or RateLimited), explicit timeouts, and retry with backoff — all of which you build, none of which you inherit.
Failure modes. Network timeouts; invalid or rotated credentials; exhausted credit; blacklisted recipient numbers; invalid sender line; provider-side API changes; duplicate sends without idempotency; and the critical one — silent failure, where Kavenegar's HTTP 200-with-error-body is collapsed into a true/false or swallowed entirely. Add to that PII leakage into logs and config-cache pitfalls (env() returning null after config:cache). Without tests or documentation, actual failure behaviour is unknown until it happens in production, and OTP failure is indistinguishable from user error until someone notices login volume dropping.
Ramp-up. Low for a Laravel developer comfortable with facades and the Kavenegar API; the integration itself is an afternoon. The real ramp-up cost is organizational: someone must own the vendor relationship, the credit balance, the credentials rotation, and the removal plan. Before any production traffic, require a one-page internal runbook covering — credential location and rotation, sender-line map (transactional vs. marketing), queue and throttle configuration, how to distinguish provider rejection from delivery failure, and the escalation path to Kavenegar support. Also require a FakeSmsSender bound in CI so tests never burn credit or depend on the network. If the runbook has no owner's name on it, the integration isn't ready.
How can I help you explore Laravel packages today?