lsnepomuceno / laravel-brazilian-ceps
A package for querying zip codes for Brazilian addresses.
Package info
github.com/lsnepomuceno/laravel-brazilian-ceps
Type:package
pkg:composer/lsnepomuceno/laravel-brazilian-ceps
2.2.0
2026-05-04 14:52 UTC
Requires
- php: >=8.1 <8.6
- ext-fileinfo: *
- ext-json: *
- ext-mbstring: *
- guzzlehttp/guzzle: ^7
- illuminate/http: ^10 || ^11 || ^12 || ^13
- illuminate/support: ^10 || ^11 || ^12 || ^13
Requires (Dev)
- nunomaduro/collision: ^6 || ^7 || ^8
- orchestra/testbench: ^8 || ^9 || ^10 || ^11
Suggests
- lsnepomuceno/laravel-a1-pdf-sign: Sign PDF files with valid x509 certificates.
README
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, }
❗ 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
❗ 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.
| Verb | URI | Invokable Controller | Route Name |
|---|---|---|---|
| GET | api/consult-cep/{cep} | LSNepomuceno\LaravelBrazilianCeps\Controllers\ConsultCepController | consult-cep.api |
❗ 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
❗ 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.'
❗ 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()], ]; } }
❗ 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}"; }
❗ 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(); } }
❗ 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}"); });
❗ 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.