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

Phone Validation Laravel Package

slvler/phone-validation

slvler/phone-validation is a Laravel package for validating phone numbers. It provides a simple validation rule to check number format and country code, helping keep user-submitted contact data clean, consistent, and reliable. Lightweight and easy to integrate into forms and APIs.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require slvler/phone-validation
php artisan vendor:publish --provider="Slvler\PhoneValidation\PhoneValidationServiceProvider"

Set the AbstractAPI key in .env (confirm the exact key name in the published config/phone-validation.php; slvler packages typically use a package-prefixed variable):

PHONE_VALIDATION_API_KEY=your_abstractapi_key

Clear cached config after adding the key:

php artisan config:clear

First call:

use Slvler\PhoneValidation\Facades\PhoneValidation;

$result = PhoneValidation::phone('+14152007986')->validate();

dump($result);
// [
//   'number' => '14152007986',
//   'valid' => true,
//   'format' => ['local' => '4152007986', 'international' => '+14152007986'],
//   'country' => ['code' => 'US', 'name' => 'United States', 'prefix' => '+1'],
//   'location' => 'California',
//   'type' => 'mobile',
//   'carrier' => 'AT&T',
// ]

Where to look first:

  1. README.md for the exact fluent method chain (phone()->validate() vs. a single validate() call).
  2. config/phone-validation.php for the env key and base URL.
  3. src/PhoneValidation.php to see how errors and HTTP responses are handled.
  4. src/Facades/PhoneValidation.php to confirm the facade accessor.
  5. If auto-discovery fails, manually register the service provider and facade alias in config/app.php.

Implementation Patterns

Custom validation rule. The natural day-to-day integration is a Laravel ValidationRule:

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Slvler\PhoneValidation\Facades\PhoneValidation;

class ValidPhoneNumber implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        try {
            $result = PhoneValidation::phone($value)->validate();
        } catch (\Throwable $e) {
            report($e);
            $fail('The :attribute could not be validated right now.');
            return;
        }

        if (! ($result['valid'] ?? false)) {
            $fail('The :attribute is not a valid phone number.');
        }
    }
}

Then in a form request:

public function rules(): array
{
    return ['phone' => ['required', 'string', new ValidPhoneNumber]];
}

Normalize before sending. Convert user input to E.164 first so the API returns stable results and your cache keys are consistent:

$e164 = (string) \Propaganistas\LaravelPhone\PhoneNumber::make($request->phone, $request->country)->formatE164();
$result = PhoneValidation::phone($e164)->validate();

Cache aggressively. Every call is a paid/limited HTTP request. Phone validity rarely changes, and carrier/line-type data changes slowly:

$result = Cache::remember("phone:".sha1($e164), now()->addDays(7), function () use ($e164) {
    return PhoneValidation::phone($e164)->validate();
});

Persist the raw response. Store the JSON in a json column alongside the normalized number so you can re-render carrier/type without re-calling the API:

$profile->update([
    'phone' => $e164,
    'phone_meta' => $result,
]);

Queue bulk validation. Imports or backfills should never hit the API in a web request. Dispatch a job per number or batched job with rate limiting:

RateLimiter::for('abstractapi', fn () => Limit::perMinute(10));

Wrap it behind your own interface. The package is thin; an adapter keeps you free to swap in Twilio Lookup or libphonenumber locally:

interface PhoneLookup
{
    public function lookup(string $e164): array;
}

Bind the package implementation in a service provider; call sites depend on the interface, not the facade.

Fake it in tests. Because it is an HTTP client under the hood, use Laravel's HTTP fake:

Http::fake([
    'phonevalidation.abstractapi.com/*' => Http::response([
        'number' => '14152007986',
        'valid' => true,
        'format' => ['international' => '+14152007986'],
        'country' => ['code' => 'US'],
        'type' => 'mobile',
    ], 200),
]);

Gotchas and Tips

  • Config cache hides new keys. Adding PHONE_VALIDATION_API_KEY to .env has no effect in production until php artisan config:cache is rerun.
  • Verify the env variable name. Do not guess based on other packages; read the published config file. A missing key typically surfaces as a 401 from AbstractAPI, not a clear Laravel exception.
  • valid: false is a 200, not an error. Branch on the valid field for business logic, and catch exceptions separately for transport/quota/auth failures.
  • Handle 401/429/5xx explicitly. The package may not throw on all error responses; dump() the result once in staging to see what a bad key and an exhausted quota actually look like.
  • Latency in the request path. Expect a few hundred milliseconds per call. Never call this on page render or in a loop over table rows — cache or queue.
  • Prefer local validation for format checks. Use propaganistas/laravel-phone (libphonenumber) for basic syntax and E.164 normalization, and reserve the API for carrier/line-type lookup where those fields are actually needed.
  • Response shape is nested. Read format.international and country.code, not top-level shortcuts. Field presence varies by country, so use null-safe access (data_get).
  • PII and logging. Phone numbers, location, and carrier are personal data. Avoid logging full responses, redact numbers in logs, and consider retention policy for the stored JSON blob.
  • Free-tier limits. AbstractAPI's free plan is small; a single un-cached contact form plus an import can exhaust it quickly. Add RateLimiter and cache.
  • No built-in retries or DTOs. The package is a thin wrapper around the HTTP client. Add your own retry with backoff for ConnectionException and 5xx, but never retry 4xx.
  • Timeouts. Set a sensible Http::timeout() globally or in your adapter; default timeouts can leave requests hanging under network issues.
  • Small community, low maintenance signal. 28 stars and one recent release means fewer eyes on edge cases. Pin the version in composer.json, read src/ before relying on undocumented behavior, and be prepared to fork — it is a small enough class to vendor if needed.
  • Facade vs. injection. If the facade alias is not registered, use app(\Slvler\PhoneValidation\PhoneValidation::class) or inject the class; both are easier to swap in tests than a static facade.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums