Product Decisions This Supports
- Whether SMS becomes a channel in the product at all. This package makes the "yes" cheap to test: SMS becomes one more method (
to46elks()) on an existing Laravel notification class rather than a new messaging subsystem. The decision is scoped to "add transactional SMS to notifications we already send," not "stand up a messaging platform."
- Provider selection as a product decision, not just a technical one. 46elks is a Nordic-focused provider. Adopting this package is effectively a bet on coverage, pricing, sender-ID regime, and compliance fit for the target market. Treat "is 46elks right for our users?" as the primary question and "is this package right?" as secondary.
- Build vs. buy vs. reuse. The alternatives are a hand-rolled channel against 46elks' REST API (roughly a day of a Laravel engineer's time) or a broader messaging vendor. This package sits in the middle: cheapest to start, cheapest to reverse, thinnest on features. Defensible when SMS is a supporting capability, not a product differentiator.
- Roadmap sequencing around framework upgrades. v1.10.12 widens support to Laravel 12 — a compatibility release, not a feature release. It de-risks a framework upgrade but ships nothing users see. If Laravel 12 is near-term, this clears a blocker; if the app stays on ≤11, it changes nothing operationally.
- Scope boundary setting with stakeholders. The package covers outbound send only. Delivery receipts, rate-limit backoff, number normalization, per-tenant credentials, batching, and billing/credit monitoring are not included and must be costed as separate line items. Making that list explicit early prevents a "we thought SMS was done" surprise at launch.
- Risk posture for a small dependency. Two stars, zero dependents, community-maintained, no SLA. Acceptable for a thin, replaceable adapter; unacceptable for anything a revenue path depends on without a written fallback. The PM decision is where on that spectrum the use case sits.
- Which SMS use cases to greenlight first. Internal operational alerts (low blast radius, tolerant of latency, easy to validate) versus end-user transactional SMS such as OTPs and order status (high blast radius, latency- and failure-sensitive, compliance-relevant). Different sequencing, different acceptance criteria — the package supports either, so the choice is product judgment.
- Cost modelling per message, not per feature. Segment-based billing (160 GSM-7 chars, dropping to 70 with any non-GSM character) means message copy is a cost lever. PMs should own the style guide for SMS templates, not delegate it entirely to engineering.
When to Consider This Package
- The product is a Laravel application already using notifications for email, database, or chat, and SMS is a natural fourth channel rather than a new integration paradigm.
- The need is straightforward outbound transactional SMS: one-way alerts, reminders, OTPs, status updates. No batching, aggregation, or bulk campaign semantics.
- 46elks is already committed or strongly favored on coverage, pricing, or an existing vendor relationship. If the provider is still open, evaluate a provider-agnostic abstraction first — otherwise you are locking in a vendor through a 2-star package.
- The team is on Laravel 12 or upgrading soon (what v1.10.12 enables) and wants a channel that tracks current Laravel releases rather than one pinned to an older framework.
- You want to avoid owning a custom integration and can accept community support with a shallow, replaceable footprint as the mitigation. Exit cost is one notification file plus a config block.
- Single-market or Nordic-first launch. Sender-ID approval, alphanumeric sender behaviour, and delivery quality are best-understood in Sweden; multi-market rollout needs per-country validation before you promise SMS anywhere else.
Look elsewhere when:
- You need delivery receipts, inbound SMS, or two-way messaging as core product functionality — this package sends and stops; DLR callbacks are separate build work.
- The use case is marketing, campaign, or bulk messaging — you want batching, scheduling, opt-out management, and analytics that this channel does not provide.
- SMS is a revenue-critical path in a multi-region product. Two stars and zero dependents is fine for an adapter you can replace in 20 lines of HTTP; it is not fine as a dependency you cannot support.
- You are not on Laravel notifications, or you need a provider-agnostic seam across multiple SMS vendors — build the abstraction first, then consider this as one driver behind it.
- Compliance requirements (data residency, audit trails, regulated-industry messaging) demand contractual guarantees that a community package and a self-serve provider account cannot give.
How to Pitch It (Stakeholders)
For executives — one paragraph. We can add transactional SMS to the product without building a messaging system: this is a small adapter that lets our existing Laravel notification code send SMS through 46elks by adding one method to notifications we already write. It is a low-cost, low-commitment way to validate whether SMS moves a metric — OTP completion, delivery-notification engagement, support-ticket reduction — before we invest in a platform. The trade-off is equally small: it is community-maintained with no vendor SLA, sends outbound only, and can be replaced by roughly a day of engineering if we outgrow it or the provider changes. The main risk is not technical, it is commercial — we are choosing a Nordic-focused SMS provider, so we should confirm coverage, per-segment cost, and sender-ID rules for our target markets before launch.
For engineering — the shape of the work. One config block, one routeNotificationFor46elks() on the notifiable, one to46elks() mapper per notification. Credentials come from env; the API user is created in the 46elks dashboard and is not the login. Everything should be queued, and retry semantics must be decided per notification because SMS is not idempotent — a retry is a second billable, user-visible message, so OTPs get $tries = 1 while status pings can retry. Failures are quiet: notify() reports success to Laravel even when the API rejects the send, so wrap sends or listen for NotificationFailed, and add a user-facing "didn't get the code?" path. Phone numbers must be normalised to E.164 at the boundary — the channel does not reformat. Message length is both a cost and a deliverability issue, so keep OTP and status copy under one 160-character segment and sanitise smart quotes from interpolated strings. Staging must never send real SMS. Pin the package version exactly: the Laravel 12 support shipped as a patch release, so a floating constraint can pull a framework change we never validated.
Ask and next steps. Approve a two-week, one-engineer spike with a defined blast radius: start with an internal ops alert to our own handset (validates credentials, sender approval, phone formatting, and delivery with zero user exposure), then one end-user flow — most likely OTP or order status. Success criteria are delivery rate, segment cost per message, and whether the flow moves its target metric. Explicitly out of scope unless separately funded: delivery receipts, multi-market sender approval, per-tenant credentials, and any bulk or campaign capability. Decision point at the end of the spike: keep, extend, or replace with a vendor-agnostic abstraction.