laravel-brazilian-ceps maintained by lsnepomuceno
Minimum requirements
- PHP: ^8.1, ^8.2, ^8.3, ^8.4, ^8.5
- Laravel: 10, 11, 12 or 13
- PHP Extensions: fileinfo, mbstring, json
Install
Require this package in your composer.json and update composer. This will download the package and the dependencies libraries also.
composer require lsnepomuceno/laravel-brazilian-ceps
Export the settings file using the command below
php artisan vendor:publish --tag=brazilian-ceps
Usage
Using CepService:
<?php
use LSNepomuceno\LaravelBrazilianCeps\Services\CepService;
class ExampleController() {
// PHP 8: Constructor property promotion
public function __construct(protected CepService $cepService) { }
public function dummyFunction(string|int $cep){
$address = $this->cepService->get($cep);
dd($address);
}
}
The returned value will have the structure below, see CepEntity:
LSNepomuceno\LaravelBrazilianCeps\Entities\CepEntity {
city: string,
cep: string,
street: string,
state: string,
uf: string,
neighborhood: string,
number: string | int | null,
complement: string | null,
}
:exclamation: By default, if the CEP is not found, the returned value will be null. If you need exception handling, the option can be enabled in the configuration file.
// config/brazilian-ceps.php
<?php
'throw_not_found_exception' => true
:exclamation: After setting the value of the "throw_not_found_exception" variable to true, remember to update your code:
<?php
use LSNepomuceno\LaravelBrazilianCeps\Services\CepService;
use LSNepomuceno\LaravelBrazilianCeps\Exceptions\CepNotFoundException;
class ExampleController() {
// PHP 8: Constructor property promotion
public function __construct(protected CepService $cepService) { }
public function dummyFunction(string|int $cep){
try {
$address = $this->cepService->get($cep);
dd($address);
} catch(CepNotFoundException $e) {
// TODO necessary
}
}
}
Route API
By default, the package will provide an API route for looking up addresses, as specified below.
:exclamation: In some cases it may be necessary to deactivate this route, in which case just change the value of the "enable_api_consult_cep_route" configuration variable to false, as example below:
// config/brazilian-ceps.php
<?php
'enable_api_consult_cep_route' => false
:exclamation: You can also change the message if the CEP is not found:
// config/brazilian-ceps.php
<?php
'not_found_message' => 'Type here the message you want.'
:exclamation: The initial middleware of the route is "guest", if it is necessary to modify it, just adjust the configuration file:
// config/brazilian-ceps.php
<?php
'api_route_middleware' => ['guest']
Validation Rule
The package provides a ValidCep rule that integrates with Laravel's validation system to validate Brazilian CEP format and, optionally, verify that the CEP actually exists.
Format validation only:
<?php
use LSNepomuceno\LaravelBrazilianCeps\Rules\ValidCep;
class AddressRequest extends FormRequest
{
public function rules(): array
{
return [
'cep' => ['required', 'string', new ValidCep],
];
}
}
Format + existence check:
Using the mustExist() method causes the rule to query the CEP providers to confirm the address exists. This performs an external HTTP request (subject to caching).
<?php
use LSNepomuceno\LaravelBrazilianCeps\Rules\ValidCep;
class AddressRequest extends FormRequest
{
public function rules(): array
{
return [
'cep' => ['required', 'string', (new ValidCep)->mustExist()],
];
}
}
:exclamation: When validation fails, the rule returns Portuguese error messages by default. You can override them via the messages() method in your Form Request:
public function messages(): array
{
return [
'cep.valid_cep' => 'The zip code is invalid.',
];
}
Address Search (Reverse Lookup)
The package provides a search() method to find CEPs by address components — the reverse of a regular CEP lookup. Multiple providers are queried in parallel and results are deduplicated by CEP code.
Providers that support address search:
- ViaCEP — structured search by UF, city, and street
- OpenStreetMap (Nominatim) — free global geocoding also added as a CEP provider fallback
<?php
use LSNepomuceno\LaravelBrazilianCeps\Facades\CEP;
// Returns a Collection of CepEntity
$addresses = CEP::search(uf: 'SP', city: 'São Paulo', street: 'Paulista');
foreach ($addresses as $address) {
echo "{$address->cep} — {$address->street}, {$address->neighborhood}";
}
:exclamation: You can also inject CepService directly:
<?php
use LSNepomuceno\LaravelBrazilianCeps\Services\CepService;
class AddressController
{
public function __construct(protected CepService $cepService) { }
public function search(string $uf, string $city, string $street)
{
$results = $this->cepService->search($uf, $city, $street);
return $results->toArray();
}
}
:exclamation: The street parameter requires at least 3 characters (ViaCEP restriction). Results are returned as a Collection<CepEntity> and are not cached.
Events
The package dispatches Laravel events on every CEP lookup, enabling listeners for logging, monitoring, analytics, or any custom behavior without modifying the core service.
| Event | When |
|---|---|
CepQueried |
Fired at the start of every get() call, before any provider is contacted |
CepFound |
Fired when a provider successfully resolves the CEP |
CepNotFound |
Fired when all providers fail to find the CEP |
Listening to events:
<?php
use LSNepomuceno\LaravelBrazilianCeps\Events\CepFound;
use LSNepomuceno\LaravelBrazilianCeps\Events\CepNotFound;
use LSNepomuceno\LaravelBrazilianCeps\Events\CepQueried;
// In your EventServiceProvider or using the #[AsEventListener] attribute:
Event::listen(CepQueried::class, function (CepQueried $event) {
Log::info("CEP lookup started: {$event->cep}");
});
Event::listen(CepFound::class, function (CepFound $event) {
Log::info("CEP found: {$event->cep}", $event->entity->toArray());
});
Event::listen(CepNotFound::class, function (CepNotFound $event) {
Log::warning("CEP not found: {$event->cep}");
});
:exclamation: All events are read-only — their properties are declared readonly. CepFound carries the resolved CepEntity via $event->entity.
Cache Results
By default, the results cache are cached and have a lifetime of 30 days, if you need to disable or change the lifetime, just update the configuration variables, as described below.
// config/brazilian-ceps.php
<?php
'cache_results' => true,
'cache_lifetime_in_days' => 30
Tests
To ensure the delivery of data, several public providers are used, with this, the need to standardize and apply tests for better code quality was seen. About 90+ tests are included in the package.
Tests can be verified through the badge 
License
The MIT License (MIT). Please see License File for more information.