Como buscar o endereço pelo CEP com o ViaCEP

O ViaCEP é um serviço gratuito que devolve o endereço de um CEP em JSON, sem cadastro nem chave. Este guia mostra como consultá-lo em JavaScript, Python e PHP, como diferenciar CEP com formato errado de CEP que não existe, como lidar com demora e falhas de rede e como preencher o formulário de endereço quando a pessoa termina de digitar o CEP.

Por Leonardo Gaertner · Publicado em

Como a consulta funciona

A consulta é um GET em https://viacep.com.br/ws/01001000/json/, com o CEP só com dígitos. A resposta traz logradouro, bairro, localidade (a cidade), uf, complemento, o código ibge e o ddd. O serviço aceita chamadas direto do navegador, então dá para consultar no próprio formulário, sem passar pelo seu servidor.

  • CEP com formato errado (menos de 8 dígitos, letras): a API responde com erro 400.
  • CEP com formato certo que não existe: a resposta é 200, mas com um campo erro. Trate esse caso, ou o formulário vai preencher campos vazios.
  • Antes de consultar, confira o formato. As máscaras e expressões do guia de máscaras ajudam.

Em JavaScript

O AbortSignal.timeout cancela a consulta se ela passar de 5 segundos, para o formulário não ficar esperando para sempre. A função devolve null para CEP inexistente e lança erro para formato inválido ou falha de rede, assim a tela pode mostrar mensagens diferentes.

JavaScript
const VIACEP = 'https://viacep.com.br/ws';

async function buscarCep(valor) {
  const cep = valor.replace(/\D/g, '');
  // Formato errado nem vai para a API: ela responderia com erro 400
  if (cep.length !== 8) throw new Error('O CEP precisa ter 8 dígitos');

  const resposta = await fetch(`${VIACEP}/${cep}/json/`, { signal: AbortSignal.timeout(5000) });
  if (!resposta.ok) throw new Error(`Erro ${resposta.status} ao consultar o CEP`);
  const dados = await resposta.json();

  // CEP com formato certo que não existe: a resposta é 200, com {"erro": "true"}
  if (dados.erro) return null;
  return {
    cep: dados.cep,
    rua: dados.logradouro,
    bairro: dados.bairro,
    cidade: dados.localidade,
    uf: dados.uf,
  };
}

Funciona no navegador e no Node.js 18 ou mais novo.

Para preencher o formulário, chame buscarCep quando o campo de CEP perder o foco (evento blur) ou quando chegar ao oitavo dígito, e coloque cada valor no campo correspondente. Deixe os campos editáveis: o CEP de cidades pequenas costuma vir sem rua nem bairro.

Em Python e PHP

As duas versões usam só a biblioteca padrão. No servidor, sempre defina um tempo limite: sem ele, uma API lenta prende o processo que atende o seu usuário.

Python
import json
import re
import urllib.request

VIACEP = "https://viacep.com.br/ws"


def buscar_cep(valor: str) -> dict | None:
    cep = re.sub(r"\D", "", valor)
    if len(cep) != 8:
        raise ValueError("O CEP precisa ter 8 dígitos")

    # urlopen lança HTTPError se a API responder com erro (4xx ou 5xx)
    with urllib.request.urlopen(f"{VIACEP}/{cep}/json/", timeout=5) as resposta:
        dados = json.load(resposta)

    if dados.get("erro"):  # CEP que não existe
        return None
    return {
        "cep": dados["cep"],
        "rua": dados["logradouro"],
        "bairro": dados["bairro"],
        "cidade": dados["localidade"],
        "uf": dados["uf"],
    }
PHP
<?php
const VIACEP = 'https://viacep.com.br/ws';

function buscarCep(string $valor): ?array
{
    $cep = preg_replace('/\D/', '', $valor);
    if (strlen($cep) !== 8) {
        throw new InvalidArgumentException('O CEP precisa ter 8 dígitos');
    }

    $contexto = stream_context_create(['http' => ['timeout' => 5]]);
    $json = @file_get_contents(VIACEP . "/$cep/json/", false, $contexto);
    if ($json === false) {
        throw new RuntimeException('Não foi possível consultar o CEP');
    }

    $dados = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
    if (!empty($dados['erro'])) { // CEP que não existe
        return null;
    }
    return [
        'cep' => $dados['cep'],
        'rua' => $dados['logradouro'],
        'bairro' => $dados['bairro'],
        'cidade' => $dados['localidade'],
        'uf' => $dados['uf'],
    ];
}

Cuidados

  • Não use o ViaCEP para validar bases inteiras de uma vez. O serviço é gratuito e pede uso moderado, e consultas em massa podem ser bloqueadas. Para muitos CEPs, guarde os resultados que já consultou.
  • Tenha um plano para quando a API estiver fora: deixe a pessoa preencher o endereço à mão. Há alternativas, como a BrasilAPI, que também consulta CEPs.
  • O CEP existir não garante que a pessoa mora ali. Para entrega, confirme o número e o complemento com ela.
  • O endereço consultado não substitui a validação no servidor, se o seu sistema depende dele.

Achou um erro neste guia? Avise por e-mail.

Perguntas frequentes

O ViaCEP é gratuito?

Sim. Não precisa de cadastro nem de chave de acesso. O serviço pede uso moderado, e consultas em massa, como validar uma base inteira, podem ser bloqueadas.

Como saber se um CEP não existe no ViaCEP?

A resposta vem com status 200 e um campo erro, em vez dos dados do endereço. Já um CEP com formato inválido, como menos de 8 dígitos, recebe erro 400.

Dá para consultar o ViaCEP direto do navegador?

Sim. O serviço permite chamadas de outros sites, então o fetch funciona direto no formulário, sem passar pelo seu servidor.

Por que o ViaCEP não trouxe a rua do meu CEP?

Em muitas cidades pequenas, um único CEP vale para a cidade inteira, e a resposta vem sem logradouro nem bairro. Nesse caso, peça para a pessoa preencher esses campos.