package Cepis; use strict; use warnings; use Exporter 5.57 qw(import); use Cepis::Address; use Cepis::Client; use Cepis::Error; use Cepis::Geo; use Cepis::Health; our $VERSION = '0.1.0'; our @EXPORT_OK = qw(lookup lookup_many health normalize_cep); my $DEFAULT_CLIENT; sub default_client { $DEFAULT_CLIENT = Cepis::Client->new unless defined $DEFAULT_CLIENT; return $DEFAULT_CLIENT; } sub lookup { return default_client()->lookup(@_); } sub lookup_many { return default_client()->lookup_many(@_); } sub health { return default_client()->health; } sub normalize_cep { return Cepis::Client::normalize_cep(@_); } 1; __END__ =encoding UTF-8 =head1 NAME Cepis - Perl client for the public CEP API at cep.is =head1 SYNOPSIS use Cepis; my $address = Cepis::lookup('01001-000'); print $address->localidade, ' ', $address->uf, "\n"; # São Paulo SP my $result = Cepis::lookup_many( [ '01001000', '99999999' ] ); print defined $result->[1] ? 'found' : 'not found', "\n"; my $health = Cepis::health(); print $health->dne, "\n"; =head1 DESCRIPTION Looks Brazilian postal codes up against L: official Correios data (DNE), refreshed every two weeks. Single lookups carry coordinates when the database has them; batches resolve up to 500 CEPs in one request. B L, L and L all ship with Perl, and the CSV reader is part of this distribution. Reaching C does need L and L, which do not ship with Perl — see L. For a script, the module-level functions are enough. In an application, build a L once and reuse it: my $client = Cepis::Client->new( timeout => 5.0, total_timeout => 15.0 ); my $address = $client->lookup('01001000'); Pointing at a local instance (the API repo brings one up with C): my $client = Cepis::Client->new( base_url => 'http://localhost:8080' ); =head2 Errors Every failure is thrown as an object under L, so one test catches the lot, and the split below it is by whether retrying helps: my $address = eval { Cepis::lookup($cep_from_form) }; if ( !$address ) { my $err = $@; if ( ref $err && $err->isa('Cepis::Error::CEPNotFound') ) { # the CEP does not exist: ask the user for another } elsif ( ref $err && $err->isa('Cepis::Error') ) { # network, server, rate limit: retry later } else { die $err; } } =head2 Field names The API surface is English, but the B — C, C, C. What you read in the JSON is what you read on the object. See L. =head2 HTTPS support L speaks HTTPS only when L 1.968 or later and L 1.49 or later are installed, and neither ships with Perl. Without them, any call against the default C throws L straight away with a message naming both modules. C reports the same thing without making a request. See L. =head1 FUNCTIONS The module-level functions all go through one shared default client, built on first use. It applies process-wide, including to third-party libraries that also use this module, so do not reconfigure it — anyone needing different settings should build their own L. Nothing is exported by default. C, C, C and C are available on request: use Cepis qw(lookup lookup_many); =head2 lookup my $address = Cepis::lookup('01001-000'); Looks up a CEP using the default configuration and returns a L. Shorthand for C<< Cepis::default_client->lookup($cep) >>; see L for the errors it throws. =head2 lookup_many my $result = Cepis::lookup_many( \@ceps ); Looks many CEPs up in one batch, using the default configuration, and returns an arrayref of the same length and order with C for the misses. Shorthand for L — read that one, especially the warning that batches carry no coordinate. =head2 health my $health = Cepis::health(); Queries the API's health using the default configuration and returns a L. Shorthand for L. =head2 normalize_cep my $number = Cepis::normalize_cep('01001-000'); # "01001000" Strips the mask and validates that 8 digits remain, throwing L otherwise. Makes no request. See L. =head2 default_client my $client = Cepis::default_client(); The L behind the functions above, built on first use. =head1 SEE ALSO L, L, L, L, L The API itself is documented at L. =head1 AUTHOR Murilo Ijanc Emurilo@ijanc.orgE =head1 LICENCE ISC. Copyright (c) 2026 Murilo Ijanc Emurilo@ijanc.orgE. =cut