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

Smsir Php Laravel Package

ipe/smsir-php

ipe/smsir-php is a PHP client for the SMS.ir API, offering a simple way to send SMS messages, handle verification codes, manage contacts and groups, and integrate SMS.ir into Laravel or standalone PHP applications with straightforward configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and pin. This package is low-traffic (16 stars, no dependents, last release Oct 2024), so treat it as a thin wrapper you may end up maintaining yourself. Install with an explicit constraint and commit the lockfile:
    composer require ipe/smsir-php:^1.0
    
  2. Get credentials from the SMS.ir panel, not the code — you need an API key from Settings → API Keys and, for OTP flows, a pre-approved verify template ID with named parameters.
  3. Read src/ before the README. With packages this small the source is the documentation; there are usually only two or three classes (a client plus one or two value objects). Confirm the constructor signature (API key position, base URL override, timeout/HTTP client injection) and whether it ships a service provider.
  4. First use case: a single transactional send. Instantiate the client with your key and send one message to your own number before wiring anything else:
    $client = new SmsIr(env('SMSIR_API_KEY'));
    $response = $client->send($mobile, 'test message');
    
    Dump the full response object. You need to see the raw shape (status, message, data.messageId, etc.) before you write any error handling — the SDK's return type is what everything else depends on.

Don't build the abstraction layer yet. Prove credentials, number format, and response shape on a single send, then move on.

Implementation Patterns

Bind the client in the container, configure from env. Even if the package ships no service provider, register it yourself so you never construct it inline:

// AppServiceProvider::register()
$this->app->singleton(SmsIr::class, fn () => new SmsIr(
    config('services.smsir.api_key')
));

Add SMSIR_API_KEY to config/services.php and .env.example. Never read env() outside config — config:cache will silently return null in production.

Wrap it in a single application-level gateway. One SmsGateway class (interface + SMS.ir implementation) that owns the SDK. This is your seam for testing, for later migrating to SMS.ir's v2 API, and for swapping providers. Keep the interface domain-shaped (sendOtp, sendBulk, getCredit), not SDK-shaped.

OTP flow — the pattern that matters most. Generate the code, persist it with an expiry and attempt counter before sending, then send via the template endpoint. Never store the plaintext code in logs. Verification of the code is your business logic; the SDK only delivers it.

Laravel notification channel. A custom channel wrapping the gateway fits naturally into Notifiable:

public function send($notifiable, SmsMessage $notification)
{
    $this->gateway->send($notifiable->routeNotificationFor('sms'), $notification->body);
}

This keeps SMS out of controllers and gives you via() to route per-user preference.

Queue bulk sends. Any send over a handful of recipients belongs in a job with $tries, $backoff, and explicit timeout. Set a timeout longer than the SDK's HTTP timeout so the job doesn't get killed mid-request and you don't know whether it landed.

Persist every send. A sms_messages table (message_id, mobile, template, status, cost, raw_response) is the cheapest debugging tool you will build. When a customer says "I never got it," you need the message ID to take to the SMS.ir panel.

Testing. Fake the gateway interface in feature tests. For unit tests of the gateway itself, inject a mock HTTP client if the SDK accepts one; otherwise wrap the SDK call in a protected method and override it in a test double. Never let the test suite touch the real API key.

Gotchas and Tips

  • HTTP 200 does not mean success. SMS.ir returns a body-level status code; a 200 response routinely carries a failure payload. Check the parsed status field, not $response->getStatusCode(), and throw a domain exception on non-1 values.
  • Normalize phone numbers at the boundary. +98912…, 0098912…, and 0912… all arrive from forms. Strip to the local 09… format (or whatever the panel expects) in one place and validate with a regex before it reaches the API — otherwise you get opaque per-recipient failures inside a bulk call.
  • Partial failure in bulk sends. One invalid recipient can fail an entire request or be silently dropped depending on the endpoint. Parse the per-recipient results array and re-queue only the failures.
  • Cost is driven by encoding and length. Persian text plus any emoji forces UCS-2 and cuts the per-part character limit roughly in half. A "short" message can bill as three SMS. Count and truncate in your own code, and validate against getCredit before large campaigns.
  • Template parameters are positionally paired with the template. Changing parameter order or count in the panel breaks the send without a code change. Keep template IDs in config, named, and note their parameter order in a comment.
  • Retries are not idempotent here. The API has no dedup key; a retried job sends a second SMS. Restrict retries to connection failures, not to sends that succeeded but returned an ambiguous body — log and alert those instead.
  • No service provider / no config publishing is likely. Don't assume php artisan vendor:publish works. Check composer.json for extra.laravel. If absent, you own the registration.
  • Pin the version and vendor-watch. With 16 stars and no dependents, there is no community pressure to fix a break. Treat the package as a dependency you may fork; keep your gateway thin so the fork is a one-file change.
  • Log the raw response on failure only, sanitized. Full request bodies contain phone numbers and OTPs — scrub them before anything hits the log channel.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons