Referência
API EvoDATA
Acesso em JSON ao cadastro público de CNPJ da Receita Federal: busca por 27 filtros combináveis, ficha completa com quadro societário, endereços do eDNE dos Correios, geolocalização por IP e tabelas de referência.
Começando
Todos os recursos vivem sob um único host, em uma versão fixada no caminho. Não há SDK: qualquer cliente HTTP serve.
| URL base | https://evodata.app/api/v1 |
|---|---|
| Protocolo | HTTPS obrigatório. Chamadas em HTTP recebem redirecionamento permanente. |
| Formato | application/json, codificado em UTF-8. Acentos saem escapados como \uXXXX, que é JSON válido. |
| Métodos | GET, e POST nos endpoints de lote, que recebem a lista no corpo. A API é de leitura. |
| Versão | v1. Campos novos podem ser acrescentados sem aviso; remoções e mudanças de tipo abrem uma versão nova. |
Primeira chamada
curl "https://evodata.app/api/v1/empresas?uf=DF&situacao=02&por_pagina=1"
Autenticação
Existem dois regimes, conforme a sensibilidade do dado:
| Recursos | Acesso |
|---|---|
/empresas, /referencias, /ceps, /localidades, /ips, /mapa, /produtos |
Chave obrigatória + plano pago. Sem chave, a resposta é 401. |
/pessoas |
Chave obrigatória + plano pago. São dados pessoais. |
Obtendo a chave
Emita em Chaves de API, no painel. A chave em claro aparece uma única vez, no momento da criação: o sistema guarda apenas um SHA-256, então nem o suporte consegue recuperá-la. Perdeu, revogue e emita outra. Cada conta pode manter até 5 chaves ativas — use uma por integração, para poder revogar uma sem derrubar as demais.
Enviando a chave
curl -H "Authorization: Bearer evd_SUA_CHAVE" \
"https://evodata.app/api/v1/pessoas?nome=MARIA&uf=SP"
O cabeçalho X-API-Key é aceito como alternativa. A chave
não é lida da query string, de propósito: parâmetro de URL vaza
em log de servidor, histórico de navegador e cabeçalho Referer.
403 plano_sem_api
— a permissão é do plano, não do saldo de créditos, então zerar ou acumular
créditos não muda nada. A busca pela interface web segue disponível a todos.
Recusas possíveis
| HTTP | erro | Significado |
|---|---|---|
401 | credencial_ausente | Nenhuma chave foi enviada. |
401 | credencial_invalida | Chave inexistente, revogada ou expirada. Os três casos respondem igual, para não confirmar que uma chave já existiu. |
403 | plano_sem_api | Chave válida, conta sem direito. Trocar a chave não resolve; mudar de plano sim. |
Limites de uso
O custo real de cada chamada é uma consulta em um PostgreSQL de ~118 GB compartilhado com outro sistema em produção. O limite protege o banco, não o servidor de aplicação.
| Situação | Limite | Chave |
|---|---|---|
| Empresas, referências e pessoas | 1000 req/min | ID da conta |
/ceps, /localidades, /ips, /mapa, /produtos | 1000 req/min | ID da conta |
Endereços, IP, mapa e produtos têm limitador próprio: são leituras por chave no MySQL, em milissegundos, e não tocam o PostgreSQL compartilhado. Para volume, prefira os endpoints de lote — 100 itens valem uma requisição.
Cache HTTP
As consultas GET de endereço e de IP trazem
Cache-Control: public, max-age=3600 e ETag. Repita a
chamada com If-None-Match: <etag> e, se nada mudou, a resposta é
304 sem corpo. /ips/meu é a exceção: depende de quem pergunta
e vem com private, no-store.
Cabeçalhos em toda resposta
X-RateLimit-Limit | Teto da janela corrente. |
|---|---|
X-RateLimit-Remaining | Quanto resta antes do bloqueio. |
Retry-After | Segundos até liberar. Presente apenas no 429. |
Convenções
Listas
Parâmetros marcados como lista aceitam duas formas equivalentes.
Valores repetidos são deduplicados e a ordem é irrelevante.
?uf=SP,RJ,MG # separados por vírgula
?uf[]=SP&uf[]=RJ # repetindo a chave
Valores fora do domínio
Filtros com domínio fechado — uf, situacao,
porte, size_class, buscar_em,
ordenar — descartam em silêncio o que não reconhecem, em vez
de devolver erro. Uma UF digitada errado simplesmente não filtra. Se a lista
inteira for inválida, o padrão do campo volta a valer.
Booleanos
Campos boolean ativam com 1, true,
on ou yes; qualquer outra coisa desativa.
Os campos marcados boolean³ são ternários: aceitam
1/true/S para sim,
0/false/N para não, e tratam
a ausência como “indiferente”, que é diferente de “não”.
Números e datas
Valores monetários aceitam ponto ou vírgula decimal: 1500.50
e 1.500,50 chegam ao mesmo lugar. Datas usam
AAAA-MM-DD e passam por validação de calendário —
2025-02-30 é descartada silenciosamente.
Datas com hora saem em ISO 8601 e em UTC (2026-11-16T04:52:10Z). Na
entrada, alterado_desde aceita data ou data e hora; sem fuso, vale UTC
(2026-11-01 é 2026-11-01T00:00:00Z, ou 21h do dia 31 em Brasília).
Buscar empresas
GET https://evodata.app/api/v1/empresas
Busca paginada sobre estabelecimentos. Ao menos um filtro é
obrigatório — uma consulta irrestrita sobre dezenas de milhões
de linhas não é atendida e devolve 422.
situacao tem padrão 02 (ativa) e não conta
como filtro para essa exigência. Chamar /empresas?situacao=02
ainda resulta em filtros_ausentes.
GET /empresas/alteracoes?alterado_desde=….
Parâmetros
Identificação
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
q |
string | Termo livre sobre razão social ou nome fantasia, conforme buscar_em. Se o valor contiver apenas dígitos (com ou sem pontuação de CNPJ) e tiver 8 ou mais deles, é reinterpretado como cnpj e o termo é descartado. |
padaria |
buscar_em |
enum | Onde q incide: razao, fantasia ou ambos. Valor desconhecido cai no padrão. |
ambos |
cnpj |
string | CNPJ completo ou raiz. Pontuação é ignorada. Tem precedência sobre q. |
62.170.939/0001-51 |
Localização
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
uf |
lista | Siglas de estado. Valores fora da tabela oficial são descartados em silêncio. | SP,RJ |
municipio |
lista | Códigos de município da Receita — não o nome. Obtenha em /referencias/municipios/{uf}. |
7107 |
bairro |
string | Nome do bairro, casamento por prefixo. | Centro |
cep |
string | Prefixo de CEP. Só dígitos são considerados. | 01310 |
Atividade econômica
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
cnae |
lista | Códigos CNAE de 7 dígitos. Busque o código em /referencias/cnae. |
4721102 |
cnae_secundario |
boolean | Quando verdadeiro, casa também no CNAE secundário do estabelecimento, não só no principal. | 1 |
natureza |
lista | Códigos de natureza jurídica. | 2135 |
Situação e porte
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
situacao |
lista | Códigos de situação cadastral. Padrão: 02 (ativa) — para incluir baixadas é preciso informar explicitamente. |
02,08 |
matriz_filial |
enum | 1 somente matrizes, 2 somente filiais. Ausente traz ambas. |
1 |
porte |
lista | Códigos de porte declarado. | 01,03 |
abertura_de |
data | Data de abertura mínima, em AAAA-MM-DD. Data inexistente no calendário é descartada. |
2024-01-01 |
abertura_ate |
data | Data de abertura máxima, em AAAA-MM-DD. |
2025-12-31 |
capital_min |
número | Capital social mínimo. Aceita 1500.50 e 1.500,50. |
10000 |
capital_max |
número | Capital social máximo. | 5000000 |
mei |
boolean³ | 1 só MEI, 0 exclui MEI, ausente é indiferente. |
1 |
simples |
boolean³ | 1 só optantes do Simples, 0 exclui, ausente é indiferente. |
1 |
Presença de contato
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
com_email |
boolean | Somente estabelecimentos com e-mail preenchido. | 1 |
com_telefone |
boolean | Somente com telefone preenchido. | 1 |
com_celular |
boolean | Somente com telefone identificado como celular. | 1 |
com_geo |
boolean | Somente com latitude e longitude resolvidas. | 1 |
Enriquecimento
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
funcionarios_min |
inteiro | Número mínimo estimado de funcionários. Vem de base de enriquecimento, não da Receita — nem todo estabelecimento tem. | 10 |
funcionarios_max |
inteiro | Número máximo estimado de funcionários. | 500 |
size_class |
lista | Classe de tamanho estimada: micro, pequena, media, grande. |
media,grande |
rating_min |
número | Avaliação mínima no Google Places, de 0 a 5. | 4.0 |
Paginação e ordenação
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
ordenar |
enum | Ordenação desejada. Pode ser recusada — veja Avisos. | abertura_desc |
pagina |
inteiro | Página, começando em 1. Valores menores que 1 viram 1. | 2 |
por_pagina |
inteiro | Itens por página. Padrão 25, teto 100. | 50 |
Resposta
{
"dados": [ { /* objeto Empresa, ver abaixo */ } ],
"paginacao": {
"pagina": 1,
"por_pagina": 25,
"total": 482163,
"total_exato": false,
"tem_proxima": true
},
"avisos": []
}
total_exato: false muda o significado de total.
Contar exatamente dezenas de milhões de linhas leva minutos, então acima de
5.000 resultados o número é a estimativa do planejador do PostgreSQL,
não uma contagem. Trate-o como ordem de grandeza: não use para paginação
exata nem para relatórios. Abaixo desse limiar a contagem é real e o campo
vem true.
avisos é um array de strings. Hoje ele só recebe uma mensagem,
quando a ordenação pedida em ordenar foi descartada: classificar
um conjunto muito grande faz o planejador trocar o índice correto por uma
varredura ordenada da tabela inteira. Nesse caso os resultados voltam na ordem
natural do índice e a requisição segue sendo 200.
Objeto Empresa
| Campo | Tipo | Descrição |
|---|---|---|
cnpj |
string | 14 dígitos, sem pontuação. |
cnpj_formatado |
string | Com máscara: 00.000.000/0000-00. |
razao_social |
string | Razão social registrada. |
nome_fantasia |
string|null | Nome fantasia, quando declarado. |
nome_exibicao |
string | Fantasia quando existe, senão razão social. Pronto para exibir. |
situacao |
string | Rótulo legível: Ativa, Baixada, Suspensa, Inapta, Nula. |
situacao_codigo |
string | Código de dois dígitos correspondente. |
ativa |
boolean | Atalho para situacao_codigo === "02". |
tipo_unidade |
string | Matriz ou Filial. |
cnae_codigo |
string | CNAE principal, 7 dígitos. |
cnae |
string | Descrição do CNAE principal. |
uf |
string | Sigla do estado. |
municipio |
string | Nome do município. |
bairro |
string|null | Bairro. |
cep |
string|null | CEP com máscara. |
endereco |
string | Logradouro, número e complemento concatenados. |
telefone |
string|null | Telefone principal com DDD, formatado. |
email |
string|null | E-mail declarado à Receita. |
porte |
string | Porte declarado, legível. |
natureza |
string | Natureza jurídica, legível. |
capital_social |
number | Capital social em reais. |
abertura |
string|null | Data de abertura em AAAA-MM-DD. |
funcionarios |
integer|null | Estimativa de funcionários. Enriquecimento. |
porte_estimado |
string|null | Classe de tamanho estimada. Enriquecimento. |
faturamento_estimado |
number|null | Faturamento estimado. Enriquecimento. |
confianca_estimativa |
string|null | Confiança das estimativas acima. Enriquecimento. |
latitude |
number|null | Latitude. Google Places. |
longitude |
number|null | Longitude. Google Places. |
avaliacao |
number|null | Nota média, 0 a 5. Google Places. |
avaliacoes_total |
integer|null | Quantidade de avaliações. Google Places. |
site |
string|null | Site oficial. Google Places. |
null
como caso comum, não como exceção.
Exemplo
curl -G "https://evodata.app/api/v1/empresas" \
--data-urlencode "uf=SP,RJ" \
--data-urlencode "cnae=4721102" \
--data-urlencode "abertura_de=2024-01-01" \
--data-urlencode "com_email=1" \
--data-urlencode "ordenar=abertura_desc" \
--data-urlencode "por_pagina=50"
Ficha de empresa
GET https://evodata.app/api/v1/empresas/{cnpj}
Retorna um único estabelecimento com todo o detalhamento. O CNPJ pode vir
com ou sem máscara e é validado pelos dígitos verificadores antes de
qualquer consulta — um CNPJ malformado devolve 422 sem tocar
o banco.
curl "https://evodata.app/api/v1/empresas/62.170.939/0001-51"
curl "https://evodata.app/api/v1/empresas/62170939000151" # equivalente
A resposta é { "dados": { … } } com todos os campos do objeto
Empresa, mais os seguintes:
| Campo | Tipo | Descrição |
|---|---|---|
cnpj_basico |
string | Raiz de 8 dígitos, compartilhada por todas as unidades. |
situacao_desde |
string|null | Data da situação cadastral atual. |
situacao_especial |
string|null | Situação especial, quando houver. |
telefone_secundario |
string|null | Segundo telefone declarado. |
cnaes_secundarios |
array | Objetos {codigo, descricao} das atividades secundárias. |
simples |
object|null | Adesão ao Simples e ao MEI — ver abaixo. |
socios |
array | Quadro societário — ver abaixo. |
unidades |
array | Matriz e filiais que compartilham a raiz — ver abaixo. |
Objeto sócio
{
"nome": "FULANO DE TAL",
"documento": "***040852**", # PF sempre parcial
"tipo": "Pessoa física",
"eh_pessoa_juridica": false,
"qualificacao": "Sócio-Administrador",
"entrada": "2019-03-12",
"faixa_etaria": "41 a 50 anos",
"representante": null
}
documento de sócio pessoa física vem parcial, no formato
***XXXXXX** — seis dígitos centrais, sem pontuação. É assim que
a própria Receita Federal publica o quadro societário; o CPF completo não
existe na origem e não há como recompô-lo. Sócio pessoa jurídica traz o CNPJ
inteiro e formatado.
Objeto simples
{
"optante": true,
"desde": "2020-01-01",
"excluido_em": null,
"mei": true,
"mei_desde": "2020-01-01",
"mei_excluido_em": null
}
Objeto unidade
Lista com todas as unidades que compartilham a mesma raiz de CNPJ, incluindo a própria consultada. Útil para navegar de uma filial à matriz.
{
"cnpj": "62170939000151",
"cnpj_formatado": "62.170.939/0001-51",
"nome_fantasia": null,
"tipo": "Matriz",
"eh_matriz": true,
"situacao": "Ativa",
"ativa": true,
"uf": "DF",
"municipio": "BRASILIA",
"cnae": "Cabeleireiros, manicure e pedicure",
"abertura": "2025-08-11"
}
Fichas em lote
POST https://evodata.app/api/v1/empresas/lote
Até 100 CNPJs por chamada, cada um devolvido com a mesma ficha de
GET /empresas/{cnpj} — é o caminho para buscar os dados das chaves que
/empresas/alteracoes devolve. A ficha é cobrada como a
avulsa, uma vez por CNPJ na competência; CNPJ inválido ou inexistente não cobra e sai com
erro na própria linha, sem derrubar o lote.
curl -X POST "https://evodata.app/api/v1/empresas/lote" \
-H "Authorization: Bearer evd_SUA_CHAVE" -H "Content-Type: application/json" \
-d '{"cnpjs": ["00000000000191", "60701190000104"]}'
{
"resultados": [
{ "cnpj": "00000000000191", "dados": { … a ficha … },
"cobranca": { "creditos": 1, "ja_paga_na_competencia": false } },
{ "cnpj": "60701190000104", "erro": "nao_encontrado", "mensagem": "…" }
],
"resumo": { "total": 2, "sucesso": 1, "creditos_debitados": 1, "saldo": 499 }
}
cobranca, creditos_debitados e saldo só vêm quando a
chamada leva chave de API.
Buscar pessoas
GET https://evodata.app/api/v1/pessoas
chave + plano pago
Busca sobre 233 milhões de pessoas físicas. Ao menos um filtro é obrigatório.
Diferente da busca de empresas, aqui não há paginação: o
parâmetro por_pagina define quantas linhas voltam, e
tem_mais indica se existem outras. Percorrer profundamente um
conjunto de centenas de milhões de linhas não é uma operação que esta base
sustente — o caminho é refinar até o recorte caber.
GET /pessoas/alteracoes?alterado_desde=….
Parâmetros
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
nome |
string | Início do nome. A base grava em maiúsculas e sem acento; a conversão é feita para você. | MARIA DA SILVA |
nome_mae |
string | Início do nome da mãe. Combinado com nome, é o par mais eficaz para desambiguar homônimos. |
ANA |
cpf |
string | CPF completo, 11 dígitos. Pontuação ignorada. Parcial é recusado — ver abaixo. | 000.000.001-91 |
rg |
string | Número de RG, igualdade exata. | 123456789 |
titulo_eleitor |
inteiro | Título de eleitor completo. | 123456789012 |
pis |
inteiro | PIS/NIT completo. | 12345678901 |
sexo |
enum | M ou F. |
F |
estado_civil |
enum | S, C, D, V ou O. |
C |
nasc_de |
data | Nascimento mínimo, AAAA-MM-DD. |
1980-01-01 |
nasc_ate |
data | Nascimento máximo, AAAA-MM-DD. |
1990-12-31 |
cbo |
string | Código de ocupação, casa por prefixo. | 2521 |
uf |
enum | Estado de um endereço conhecido. | SP |
cidade |
string | Cidade, por prefixo e sem acento. | SAO PAULO |
bairro |
string | Bairro, por prefixo. | CENTRO |
logradouro |
string | Nome do logradouro, sem “Rua” ou “Av.”. | PAULISTA |
cep |
string | CEP completo, 8 dígitos. | 01310-100 |
uf_emissao |
enum | UF de emissão do RG. | SP |
email |
string | E-mail completo ou o começo dele. Domínio sozinho é recusado — ver abaixo. | joao.silva@ |
ddd |
inteiro | DDD, de 11 a 99. | 11 |
telefone |
inteiro | Número completo, sem DDD e sem pontuação. | 999998888 |
por_pagina |
inteiro | Linhas retornadas. Padrão 25, teto 100. | 50 |
422 filtro_nao_suportado:
CPF parcial. A coluna é
char(11) e um prefixo
obrigaria varredura sobre 233 milhões de linhas. Informe os 11 dígitos.
Domínio de e-mail (
@provedor.com). Nenhum índice
cobre o final de uma string, e a coluna dominio da base guarda uma
classificação (PUBLICO), não o domínio. Aceitar o filtro devolveria
resultado plausível e errado.
Resposta
{
"dados": [
{
"id": 2091705,
"nome": "MARIA APARECIDA SILVA",
"cpf": "***.456.789-**",
"nome_mae": "ROSA MARIA BELLONI",
"sexo": "F",
"sexo_descricao": "Feminino",
"nascimento": "1975-03-22",
"idade": 51,
"estado_civil": "C",
"estado_civil_descricao": "Casado(a)",
"cbo": "2521",
"cidade": "SAO PAULO",
"uf": "SP",
"ddd": 11,
"telefone": 999998888
}
],
"paginacao": {
"por_pagina": 25,
"retornados": 25,
"tem_mais": true,
"amostra": false
},
"consulta": {
"condutor": "pessoas",
"ms": 32
}
}
amostra: true muda o significado do resultado.
Quando o filtro mais seletivo ainda casa candidatos demais — uma UF sozinha,
por exemplo —, a busca lê no máximo 4.000 candidatos e filtra dentro deles.
O que volta é um recorte válido, mas não é “os primeiros N do conjunto”
nem permite concluir que não existem outros. Para cobertura, refine até
amostra vir false.
O bloco consulta é diagnóstico: condutor revela por qual
tabela a consulta entrou, o que explica por que uma combinação ficou lenta.
Filtros exatos — CPF, telefone, e-mail, CEP, PIS — conduzem por índice único e
respondem em milissegundos; uf ou sexo sozinhos conduzem
mal e tendem a virar amostra ou 503.
Exemplo
curl -H "Authorization: Bearer evd_SUA_CHAVE" -G "https://evodata.app/api/v1/pessoas" \
--data-urlencode "nome=MARIA" \
--data-urlencode "nome_mae=ANA" \
--data-urlencode "uf=SP" \
--data-urlencode "por_pagina=50"
Ficha de pessoa
GET https://evodata.app/api/v1/pessoas/{id}
chave + plano pago
O id é o identificador interno devolvido no campo id da
busca — não é o CPF, que nunca sai em claro por nenhum endpoint.
A resposta traz todos os campos da linha de busca, mais os blocos:
| Bloco | Tipo | Conteúdo |
|---|---|---|
obito_em |
string|null | Data de óbito, quando registrada na origem. |
nome_pai |
string|null | Nome do pai. |
rg |
string|null | Número do RG, com orgao_emissor e uf_emissao. |
nacionalidade |
string|null | Nacionalidade declarada. |
situacao_cadastral |
integer|null | Código de situação, com situacao_cadastral_em. |
documentos |
object | pis, titulo_eleitor, zona, secao. |
score |
object|null | csb8 e csba com suas faixas de risco, de 0 a 1000. |
perfil_financeiro |
object|null | classe, codigo_classe e faixa de renda estimada. |
enderecos |
array | Até 12, do mais recente ao mais antigo. |
telefones |
array | Até 30, com tipo_descricao legível. |
emails |
array | Até 25, com qualidade e blacklist. |
vinculos |
array | Até 40 relações familiares, resolvidas nos dois sentidos do parentesco. |
***.456.789-** quando a
origem traz o documento da contraparte, e ***.***.***-** quando não
traz. A tabela de parentesco grava apenas uma das direções, então a contraparte
falta com frequência — trate a segunda forma como caso normal.
Pessoas em lote
POST https://evodata.app/api/v1/pessoas/lote
chave + plano pago
Até 100 ids por chamada, cada um com a ficha completa — o caminho
para os dados das chaves de /pessoas/alteracoes.
Cobrança e erros por linha como no lote de empresas.
curl -X POST "https://evodata.app/api/v1/pessoas/lote" \
-H "Authorization: Bearer evd_SUA_CHAVE" -H "Content-Type: application/json" \
-d '{"ids": [1048576, 2097152]}'
Tabelas de referência
Os filtros cnae e municipio esperam códigos.
Estes dois endpoints resolvem nome para código e servem bem a campos de
autocompletar.
Buscar CNAE
GET https://evodata.app/api/v1/referencias/cnae?q={termo}
Busca textual na descrição das atividades. Termos com menos de 2 caracteres
devolvem lista vazia e 200 — não é erro.
curl "https://evodata.app/api/v1/referencias/cnae?q=padaria"
{
"dados": [
{ "codigo": 1091102, "descricao": "Fabricação de produtos de padaria e confeitaria com predominância de produção própria" },
{ "codigo": 4721101, "descricao": "Padaria e confeitaria com predominância de produção própria" },
{ "codigo": 4721102, "descricao": "Padaria e confeitaria com predominância de revenda" }
]
}
codigo aqui volta como número, sem o zero à
esquerda que alguns CNAEs têm. Ao repassar para o filtro cnae,
trate como texto de 7 posições.
Municípios por UF
GET https://evodata.app/api/v1/referencias/municipios/{uf}
Todos os municípios de um estado, com o código que o filtro
municipio espera. A sigla não diferencia maiúsculas.
curl "https://evodata.app/api/v1/referencias/municipios/df"
{ "dados": [ { "codigo": "9701", "nome": "BRASILIA" } ] }
Endereços e CEP
A base de endereçamento é o eDNE, o Diretório Nacional de Endereços dos Correios: 1,57 milhão de CEPs, 11,5 mil localidades e 83 mil bairros. Os endpoints são públicos, como as tabelas de referência, e não debitam crédito.
Nem todo CEP é de rua. O campo tipo diz de onde ele vem, e muda quais
campos vêm preenchidos:
tipo | O que é | Campos próprios |
|---|---|---|
logradouro | Rua, avenida, praça — 97% dos CEPs. | tipo_logradouro, logradouro, numeracao |
localidade | CEP único de cidade pequena, distrito ou povoado que não tem CEP por rua. | Só cidade, distrito e UF. |
grande_usuario | Órgão, empresa ou condomínio com CEP exclusivo. | nome, endereco |
unidade_operacional | Agência ou unidade dos Correios. | nome, endereco, caixas_postais |
caixa_postal_comunitaria | Caixa postal comunitária. | nome, endereco, caixas_postais |
especial | CEP promocional dos Correios, como o do Papai Noel. | nome |
cidade é sempre o município. Um CEP de distrito traz o
município em cidade e o distrito em distrito, e o
codigo_ibge é o do município — o eDNE só publica código IBGE para
município. Assim o par cidade + codigo_ibge casa com
qualquer outra base municipal.
GET /ceps/alteracoes e
GET /localidades/alteracoes, com alterado_desde=….
Consultar CEP
GET https://evodata.app/api/v1/ceps/{cep}
Aceita o CEP com ou sem máscara. Sete dígitos ganham o zero à
esquerda: é o CEP de São Paulo, de 01000-000 a
09999-999, depois de passar por uma planilha que o guardou como
número. Nenhum CEP começa com 00, então menos de sete dígitos é
recusado com 422 cep_invalido.
curl "https://evodata.app/api/v1/ceps/01310-200"
{
"dados": {
"cep": "01310200",
"cep_formatado": "01310-200",
"tipo": "logradouro",
"nome": null,
"endereco": "Avenida Paulista",
"tipo_logradouro": "Avenida",
"logradouro": "Paulista",
"complemento": "- de 1512 a 2132 - lado par",
"numeracao": { "inicial": 1512, "final": 2132, "lado": "par" },
"bairro": "Bela Vista",
"distrito": null,
"cidade": "São Paulo",
"uf": "SP",
"codigo_ibge": "3550308",
"localidade_id": 9668,
"caixas_postais": []
}
}
Objeto endereço
| Campo | Tipo | Descrição |
|---|---|---|
cep |
string | 8 dígitos, sem pontuação. |
cep_formatado |
string | Com máscara: 00000-000. |
tipo |
string | Fonte do CEP — tabela acima. |
nome |
string|null | Nome do grande usuário, da agência ou da caixa comunitária. |
endereco |
string|null | Linha pronta para exibir. Em logradouro, tipo e nome (Avenida Paulista); nos demais tipos, o endereço do cadastro, com número. |
tipo_logradouro |
string|null | Rua, Avenida, Travessa… São 385 tipos no eDNE. |
logradouro |
string|null | Nome sem o tipo: Paulista. |
complemento |
string|null | Trecho coberto, como os Correios publicam: - de 612 a 1510 - lado par. |
numeracao |
object|null | inicial, final e lado — ver abaixo. Nulo quando o CEP cobre a rua toda. |
bairro |
string|null | Bairro. |
distrito |
string|null | Distrito ou povoado, quando o CEP fica fora da sede do município. |
cidade |
string | Município. |
uf |
string | Sigla do estado. |
codigo_ibge |
string|null | Código IBGE do município, 7 dígitos. |
localidade_id |
integer|null | Chave da localidade, para /localidades/{id}. |
caixas_postais |
array | Faixas {inicial, final} de caixa postal. Só em agência e caixa comunitária; vazio nos demais. |
Numeração
Rua longa tem um CEP por trecho. numeracao diz qual trecho: de
inicial a final, do lado
par, impar, ambos, direito ou
esquerdo. final de 99999 ou mais significa “até o fim da
rua”. Em rodovia a numeração é o quilômetro e pode ter fração:
116.302 é o km 116,302.
CEPs em lote
POST https://evodata.app/api/v1/ceps/lote
Até 100 CEPs por chamada, resolvidos numa
consulta só. Cada item volta na mesma posição em que foi enviado, com
dados ou com erro — um CEP inválido não derruba os outros.
curl -X POST "https://evodata.app/api/v1/ceps/lote" \
-H "Content-Type: application/json" \
-d '{"ceps": ["01310-100", "1310100", "99999999", "123"]}'
{
"resultados": [
{ "cep": "01310100", "dados": { /* objeto endereço */ } },
{ "cep": "01310100", "dados": { /* o mesmo: 7 dígitos, zero completado */ } },
{ "cep": "99999999", "erro": "nao_encontrado", "mensagem": "CEP não consta no eDNE dos Correios." },
{ "cep": "123", "erro": "cep_invalido", "mensagem": "CEP deve ter 8 dígitos." }
],
"resumo": { "total": 4, "sucesso": 2 }
}
Endereço → CEP
GET https://evodata.app/api/v1/ceps?uf=&cidade=&logradouro=
O caminho inverso: descobrir o CEP de um endereço. Devolve só CEPs de
logradouro.
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
uf |
enum | Obrigatório. Sigla do estado. | SP |
cidade |
string | Obrigatório. Nome completo do município. | São Paulo |
logradouro |
string | Obrigatório. Início do nome, 3 letras ou mais, com ou sem o tipo. | Av. Paulista |
bairro |
string | Início do nome do bairro. | Bela Vista |
numero |
string | Número do imóvel. Devolve só o CEP do trecho que o contém. Em rodovia, o km: 116,302. |
1578 |
por_pagina |
inteiro | Itens retornados. Padrão 25, teto 100. | 10 |
Com numero, cada rua traz só o CEP do trecho que contém o número;
rua sem seccionamento (numeracao: null) entra sempre, porque o CEP
dela vale para qualquer número. Por isso o exemplo abaixo traz, além da
Avenida Paulista, outras ruas cujo nome começa por “Paulista”.
Acento e caixa não importam: sao paulo encontra
São Paulo. O tipo digitado à frente do nome — Av.,
R, Travessa — é tentado com e sem, porque o eDNE guarda
o nome sem ele e há logradouros cujo nome começa pelo tipo.
curl -G "https://evodata.app/api/v1/ceps" \
--data-urlencode "uf=SP" \
--data-urlencode "cidade=sao paulo" \
--data-urlencode "logradouro=Av. Paulista" \
--data-urlencode "numero=1578"
# resposta abreviada
{
"dados": [
{ "cep": "01310200", "endereco": "Avenida Paulista", "complemento": "- de 1512 a 2132 - lado par",
"numeracao": { "inicial": 1512, "final": 2132, "lado": "par" }, /* … */ },
{ "cep": "08190461", "endereco": "Viela Paulista", "numeracao": null, /* … */ },
{ "cep": "05440001", "endereco": "Rua Paulistânia", "complemento": "- de 453/454 ao fim", /* … */ }
],
"paginacao": { "por_pagina": 25, "retornados": 3, "tem_mais": false }
}
tem_mais avisa que existem outros CEPs além dos
devolvidos. Com prefixo curto numa cidade grande isso é esperado — refine com
mais letras, bairro ou numero. Lista vazia é
200, não erro.
Localidades e bairros
GET https://evodata.app/api/v1/localidades?uf={uf}
Municípios, distritos e povoados de um estado, com código IBGE e faixas de CEP.
Filtre com nome (início do nome, sem distinção de acento) e
tipo (municipio, distrito ou
povoado).
curl "https://evodata.app/api/v1/localidades?uf=AC"
{
"dados": [
{
"id": 1,
"nome": "Acrelândia",
"nome_abreviado": "Acrelândia",
"tipo": "municipio",
"uf": "AC",
"codigo_ibge": "1200013",
"cep": "69945000",
"codificacao": "cep_unico",
"municipio": null,
"faixas_cep": [ { "inicial": "69945000", "final": "69949999", "abrangencia": "total" } ]
},
{
"id": 11059,
"nome": "Campinas",
"tipo": "distrito",
"uf": "AC",
"codigo_ibge": "1200385", # o do município, Plácido de Castro
"cep": "69929000",
"codificacao": "cep_unico",
"municipio": { "id": 13, "nome": "Plácido de Castro" },
/* … */
}
]
}
| Campo | Tipo | Descrição |
|---|---|---|
id |
integer | Chave da localidade no eDNE. É o localidade_id dos CEPs. |
tipo |
enum | municipio, distrito ou povoado. |
codigo_ibge |
string|null | Do município; para distrito e povoado, do município a que pertencem. |
cep |
string|null | CEP único, quando a localidade não tem CEP por rua. |
codificacao |
enum | cep_unico — um CEP para a localidade toda; por_logradouro — CEP por rua, consulte /ceps; no_municipio — distrito cujas ruas estão na codificação do município; em_codificacao — em transição para CEP por rua. |
municipio |
object|null | {id, nome} do município, para distrito e povoado. |
faixas_cep |
array | {inicial, final, abrangencia}. abrangencia é total (o município inteiro) ou sede_urbana. |
GET https://evodata.app/api/v1/localidades/{id}
Uma localidade, com outras_denominacoes: nomes anteriores e grafias
que os Correios aceitam (S C do Sul para São Caetano do Sul). Serve
para casar endereço antigo ou digitado de outro jeito.
GET https://evodata.app/api/v1/localidades/{id}/bairros
Bairros da localidade em ordem alfabética, com id, nome,
nome_abreviado e faixas_cep. As faixas de um bairro raramente
são contínuas — Barcelona, em São Caetano do Sul, tem dez. 14% dos bairros não
têm faixa própria no eDNE e saem com a lista vazia.
curl "https://evodata.app/api/v1/localidades/9642/bairros"
{
"localidade": { "id": 9642, "nome": "São Caetano do Sul", "uf": "SP" },
"dados": [
{
"id": 24379,
"nome": "Barcelona",
"nome_abreviado": "Barcelona",
"faixas_cep": [
{ "inicial": "09550001", "final": "09550010" },
{ "inicial": "09550050", "final": "09550051" },
/* … */
]
}
]
}
GET https://evodata.app/api/v1/localidades/{id}/logradouros
Em 4.128 municípios os Correios têm um CEP para a cidade inteira (e às vezes um por
distrito), e o eDNE não traz o nome de rua nenhuma. Para eles, este endpoint lista as
ruas do OpenStreetMap — cerca de 458 mil, atualizadas toda semana —, cada
uma com o CEP da localidade em que está, a coordenada e cep_criterio:
cep_unico_do_municipio— o município tem um CEP só; não há o que errar.poligono_do_distrito— a rua está dentro do limite do distrito no OpenStreetMap.distrito_mais_proximo— o OpenStreetMap não desenha os distritos dali, e vale o mais próximo da rua. É estimativa: confira.
Conferido contra as ruas que trazem etiqueta de CEP no próprio OpenStreetMap: 98% de acerto
pelo polígono, 97% pela proximidade. Aceita nome (início do nome da rua),
pagina e por_pagina. Município com CEP por rua responde 422 — ali quem
responde é /ceps, que nesses mesmos municípios também passa a devolver as ruas do
OpenStreetMap, com fonte: "openstreetmap".
curl "https://evodata.app/api/v1/localidades/1/logradouros?nome=Avenida&por_pagina=1"
{
"localidade": { "id": 1, "nome": "Acrelândia", "uf": "AC", "codigo_ibge": "1200013" },
"dados": [
{
"cep": "69945000",
"endereco": "Avenida 1",
"tipo": "localidade",
"distrito": null,
"cidade": "Acrelândia",
"fonte": "openstreetmap",
"cep_criterio": "cep_unico_do_municipio",
"coordenadas": { "latitude": -10.0727304, "longitude": -67.0622937, "precisao": "logradouro", "raio_m": 25 },
/* … os demais campos de um CEP */
}
],
"paginacao": { "pagina": 1, "por_pagina": 1, "retornados": 1, "total": 125, "tem_mais": true },
"fonte": { "nome": "OpenStreetMap", "atribuicao": "© colaboradores do OpenStreetMap — dados sob a licença ODbL (openstreetmap.org/copyright)" }
}
coordenadas e as ruas de município sem CEP por
logradouro vêm do OpenStreetMap, e nunca entram na tabela dos Correios.
Alterações desde uma data
Para alimentar uma base própria e mantê-la em dia sem baixar tudo de novo: cada conjunto tem a lista do que entrou, mudou ou saiu desde uma data. Funciona para empresas, CEPs, localidades e pessoas.
GET https://evodata.app/api/v1/empresas/alteracoes
GET https://evodata.app/api/v1/ceps/alteracoes
GET https://evodata.app/api/v1/localidades/alteracoes
GET https://evodata.app/api/v1/pessoas/alteracoes
chave + plano pago
| Conjunto | Chave na lista | Registro desde | Dados de cada chave |
|---|---|---|---|
| empresas | cnpj |
14/10/2026 18:26 UTC | POST /empresas/lote |
| ceps | cep |
13/10/2026 05:10 UTC | POST /ceps/lote |
| localidades | localidade_id |
27/09/2026 15:57 UTC | GET /localidades/{id} e /bairros |
| pessoas | id |
17/07/2026 13:10 UTC | POST /pessoas/lote |
Por que não um filtro por updated_at: nenhuma das fontes diz
quando um registro mudou. O cadastro de CNPJ é regravado inteiro a cada carga mensal, e o
dos Correios a cada importação — filtrar por essa data devolveria tudo ou nada. A data é
produzida aqui, comparando cada carga da fonte com a anterior; alterado_em é
quando essa comparação foi publicada.
Parâmetros
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
alterado_desde |
data ISO 8601 | Devolve o que foi publicado a partir desta data. Data sem hora é 00:00; sem fuso, UTC. Compara com alterado_em, não com base_de. Não pode ser anterior a registro.inicio. |
2026-11-01 |
cursor |
texto | O proximo_cursor da resposta anterior. Continua exatamente de onde ela parou. Com cursor, alterado_desde é ignorada. |
1843 |
por_pagina |
inteiro | Itens por página. Padrão 1000, teto 5000. | 1000 |
Um dos dois, alterado_desde ou cursor, é obrigatório. Formatos aceitos
na data: 2026-11-01, 2026-11-01T03:00:00Z,
2026-11-01T00:00:00-03:00. Uma data posterior à última comparação devolve a
lista vazia — e um proximo_cursor que já serve para as próximas.
Resposta
curl "https://evodata.app/api/v1/empresas/alteracoes?alterado_desde=2026-11-01&por_pagina=2"
{
"dados": [
{ "cnpj": "00000000000191", "tipo": "alteracao", "partes": ["estabelecimento", "socios"],
"alterado_em": "2026-11-16T04:52:10Z", "base_de": "2026-11-15T18:26:17Z" },
{ "cnpj": "60701190000104", "tipo": "inclusao", "partes": ["estabelecimento"],
"alterado_em": "2026-11-16T04:52:10Z", "base_de": "2026-11-15T18:26:17Z" }
],
"paginacao": { "por_pagina": 2, "retornados": 2, "tem_mais": true, "proximo_cursor": "1843" },
"registro": { "inicio": "2026-10-14T18:26:17Z", "ultima_comparacao": "2026-11-16T04:52:10Z",
"base_de": "2026-11-15T18:26:17Z" },
"dados_completos": "POST /v1/empresas/lote"
}
| Campo | Tipo | Descrição |
|---|---|---|
dados[].cnpj / cep / localidade_id / id |
string|integer | A chave do registro, conforme o conjunto (tabela acima). |
dados[].tipo |
string | inclusao (chave nova), alteracao (algo nela mudou) ou exclusao (saiu da fonte: apague na sua base). |
dados[].partes |
array | O que mudou — ver a tabela abaixo. Na inclusão e na exclusão, a parte principal. |
dados[].alterado_em |
string | Quando a comparação foi publicada aqui. É com ela que alterado_desde compara. |
dados[].base_de |
string|null | Data dos dados na fonte, quando ela informa (no CNPJ, a carga da Receita). |
paginacao.tem_mais |
boolean | Há mais itens depois desta página. |
paginacao.proximo_cursor |
string | Passe em cursor para a próxima página. Guarde o último: é dele que a próxima sincronização continua. |
registro.inicio |
string | Desde quando o registro existe. Antes disso, 422 anterior_ao_registro. |
registro.ultima_comparacao |
string|null | Quando a fonte foi comparada pela última vez, com ou sem mudança. |
registro.base_de |
string|null | Data da fonte nessa última comparação. |
dados_completos |
string | Onde buscar os dados de cada chave. |
| Conjunto | Partes | Quando compara |
|---|---|---|
| empresas | estabelecimento, empresa, socios, simples — mudança no CNPJ básico aparece em todos os estabelecimentos dele.
A base não apaga CNPJ: empresa baixada vem como alteracao (da situação cadastral), não como exclusão. |
Depois de cada carga mensal da Receita, de madrugada |
| ceps | endereco (eDNE), coordenadas (OpenStreetMap, arredondadas a ~11 m) | Quando o eDNE é reimportado e toda semana, com o mapa |
| localidades | localidade, faixas, bairros, denominacoes | Quando o eDNE é reimportado |
| pessoas | pessoa, scores, poder_aquisitivo, tse, pis, enderecos, telefones, emails | A base é um retrato fixo: até a próxima recarga, nada muda e a lista vem vazia |
Sincronizar uma base própria
- Carga inicial pela consulta completa (busca, exportação ou lote). Anote quando ela começou.
- Primeira sincronização com
alterado_desde= essa data. Se a sua carga é anterior aregistro.inicio, useregistro.inicio— o que mudou entre as duas não está no registro. - Siga
proximo_cursoratétem_maisserfalse, e guarde o último cursor. - Nas próximas, só o
cursorguardado: continua exatamente de onde parou, sem repetir nem pular, mesmo que uma comparação nova tenha sido publicada no meio. - Para cada chave, busque os dados no
/lotedo conjunto e grave por cima (upsert) — ou apague, emexclusao. A lista não cobra crédito; a ficha cobra, como sempre.
# 1. primeira vez: pela data
curl "https://evodata.app/api/v1/empresas/alteracoes?alterado_desde=2026-11-01T00:00:00Z&por_pagina=5000"
# 2. páginas seguintes, e toda sincronização depois: pelo cursor guardado
curl "https://evodata.app/api/v1/empresas/alteracoes?cursor=1843&por_pagina=5000"
# 3. os dados das chaves, até 100 por chamada
curl -X POST "https://evodata.app/api/v1/empresas/lote" -H "Authorization: Bearer evd_SUA_CHAVE" \
-H "Content-Type: application/json" -d '{"cnpjs": ["00000000000191", "60701190000104"]}'
# pessoas: o mesmo, com a chave de API
curl -H "Authorization: Bearer evd_SUA_CHAVE" "https://evodata.app/api/v1/pessoas/alteracoes?alterado_desde=2026-11-01"
O laço inteiro, em Python
import requests
API = "https://evodata.app/api/v1"
H = {"Authorization": "Bearer evd_SUA_CHAVE"}
def sincronizar(cursor=None, desde="2026-11-01"):
while True:
q = {"cursor": cursor} if cursor else {"alterado_desde": desde}
r = requests.get(f"{API}/empresas/alteracoes", params={**q, "por_pagina": 5000}, headers=H).json()
apagar = [d["cnpj"] for d in r["dados"] if d["tipo"] == "exclusao"]
buscar = [d["cnpj"] for d in r["dados"] if d["tipo"] != "exclusao"]
for i in range(0, len(buscar), 100):
lote = requests.post(f"{API}/empresas/lote", json={"cnpjs": buscar[i:i+100]}, headers=H).json()
gravar([x for x in lote["resultados"] if "dados" in x]) # upsert na sua base
remover(apagar)
cursor = r["paginacao"]["proximo_cursor"]
guardar_cursor(cursor) # só depois de gravar a página
if not r["paginacao"]["tem_mais"]:
return cursor
registro.inicio o registro não existe e a API responde 422
anterior_ao_registro: para esse período, a carga é a consulta completa. O registro
guarda 400 dias; cursor mais antigo que isso
responde 422 cursor_expirado, e o caminho é refazer a carga completa. Sincronize
ao menos uma vez nesse prazo.
Geolocalização por IP
País, estado, cidade e coordenadas aproximadas de um IPv4 ou IPv6, a partir do
GeoLite2-City: 5,8 milhões de redes, atualizadas automaticamente a
cada release. No Brasil a cidade vem com codigo_ibge, que liga o IP ao
município do eDNE — de um IP se chega às faixas de CEP e aos bairros da cidade em
/localidades.
raio_precisao_km, e em rede móvel ou em provedor que concentra a saída
numa capital a cidade pode ser a do provedor. Use para região, fuso e idioma — não
para endereço.
Consultar um IP
GET https://evodata.app/api/v1/ips/{ip}
curl "https://evodata.app/api/v1/ips/177.52.140.1"
{
"dados": {
"ip": "177.52.140.1",
"versao": 4,
"rede": "177.52.140.0/22",
"continente_codigo": "SA",
"continente": "América do Sul",
"pais_codigo": "BR",
"pais": "Brasil",
"pais_uniao_europeia": false,
"pais_registro_codigo": "BR",
"subdivisao_codigo": "MG",
"subdivisao": "Minas Gerais",
"cidade": "Sete Lagoas",
"cidade_geoname_id": 3447624,
"codigo_ibge": "3167202",
"codigo_postal": "35700",
"latitude": -19.4352,
"longitude": -44.2815,
"raio_precisao_km": 5,
"fuso_horario": "America/Sao_Paulo",
"anycast": false
},
"fonte": {
"base": "GeoLite2-City",
"release": "2026.09.25",
"gerada_em": "2026-09-22T20:59:22+00:00",
"atribuicao": "This product includes GeoLite2 Data created by MaxMind, available from https://www.maxmind.com."
}
}
| Campo | Tipo | Descrição |
|---|---|---|
rede |
string | Rede em CIDR. Todo IP dela tem esta mesma resposta — guarde a rede, não o IP, se for cachear. |
pais_codigo |
string|null | ISO 3166-1 alfa-2. Nomes de continente e país vêm em português. |
pais_registro_codigo |
string|null | Onde o bloco foi registrado. Difere do país de uso em operadoras multinacionais. |
subdivisao_codigo |
string|null | No Brasil, a sigla da UF. |
cidade |
string|null | Nulo quando a rede só é localizada até o país ou o estado — caso comum fora das capitais. |
codigo_ibge |
string|null | Só Brasil. Município do eDNE casado por nome e UF. |
codigo_postal |
string|null | No Brasil, os 5 primeiros dígitos do CEP — o setor, não o endereço. |
latitude, longitude |
number|null | Ponto aproximado. |
raio_precisao_km |
integer|null | Raio em torno do ponto em que o IP deve estar. Leve-o junto com as coordenadas. |
fuso_horario |
string|null | Fuso IANA, como America/Sao_Paulo. |
anycast |
boolean | Rede que responde de vários lugares (DNS público, CDN). Localização só indicativa. |
IPv4 escrito como IPv6 (::ffff:177.52.140.1) é consultado como IPv4. IP
de rede privada ou reservada recebe 422 ip_reservado, e IP público fora
das redes do GeoLite2, 404 nao_encontrado.
O IP de quem chama
GET https://evodata.app/api/v1/ips/meu
A mesma resposta, para o IP com que a requisição chegou. Útil no navegador, para pré-preencher estado e cidade num formulário.
Vários IPs
POST https://evodata.app/api/v1/ips/lote
curl -X POST "https://evodata.app/api/v1/ips/lote" \
-H "Content-Type: application/json" \
-d '{"ips": ["177.52.140.1", "2804:14c::1", "10.0.0.1", "abc"]}'
{
"resultados": [
{ "ip": "177.52.140.1", "dados": { /* … */ } },
{ "ip": "2804:14c::1", "dados": { /* … */ } },
{ "ip": "10.0.0.1", "erro": "ip_reservado", "mensagem": "…" },
{ "ip": "abc", "erro": "ip_invalido", "mensagem": "…" }
],
"resumo": { "total": 4, "sucesso": 2 },
"fonte": { /* … */ }
}
fonte.release diz qual está
em uso.
Mapa e distâncias
Sobre o OpenStreetMap do Brasil, recarregado toda semana: 1,5 milhão de
logradouros, 1,6 milhão de endereços com número, 800 mil pontos de interesse (comércio,
serviços, saúde, educação, transporte) e os polígonos de município, distrito e bairro.
Todo ponto pode ser dado como CEP ou como coordenada
"lat,lon".
A ponte é o CEP: cada CEP do eDNE ganhou uma coordenada, e /ceps/{cep} passou
a trazer o campo coordenadas. Como um CEP é uma rua ou um trecho dela — não
uma porta —, a coordenada vem sempre com precisao e raio_m:
precisao | Como o ponto foi achado |
|---|---|
numero | Endereços do OSM na mesma rua, dentro da faixa de numeração do CEP |
cep | Objetos e vias do OSM marcados com este CEP |
logradouro | A rua do CEP, encontrada no OSM pelo nome |
logradouro_similar | Rua de mesmo nome com outro tipo (ex.: Travessa × Rua) — confira |
bairro | Centro do bairro |
localidade | Distrito ou povoado |
municipio | Sede do município |
km_linha_reta é a menor
distância sobre a superfície da Terra. km_estrada e minutos_carro vêm do
servidor de rotas sobre o mesmo mapa (perfil carro, sem trânsito) e são null quando
ele está desligado — nunca uma linha reta multiplicada por um fator. incerteza_km
soma o raio_m dos dois pontos: um CEP resolvido só até a sede do município pode
estar a quilômetros do endereço real, e a distância herda isso.
Distância e matriz
GET https://evodata.app/api/v1/distancia?origem=…&destino=…
curl "https://evodata.app/api/v1/distancia?origem=01310-100&destino=20040-002"
{
"dados": {
"origem": {
"status": "ok", "entrada": "01310-100", "tipo": "cep", "cep": "01310100",
"latitude": -23.5649616, "longitude": -46.6517717,
"precisao": "numero", "raio_m": 517,
"endereco": "Avenida Paulista, Bela Vista, São Paulo/SP", "codigo_ibge": "3550308"
},
"destino": { /* … Avenida Rio Branco, Centro, Rio de Janeiro/RJ */ },
"km_linha_reta": 362.443,
"incerteza_km": 0.559,
"rumo_graus": 79
},
"fonte": {
"base": "OpenStreetMap (extrato Brasil, Geofabrik)",
"dados_de": "2026-10-07T20:20:35+00:00",
"atribuicao": "© colaboradores do OpenStreetMap — dados sob a licença ODbL (openstreetmap.org/copyright)"
}
}
POST https://evodata.app/api/v1/distancia/matriz
curl -X POST "https://evodata.app/api/v1/distancia/matriz" \
-H "Content-Type: application/json" \
-d '{"origens": ["01310100"], "destinos": ["20040002", "-15.7939,-47.8828"]}'
Até 100 origens × 100 destinos. distancias[i][j] é de origens[i]
a destinos[j], ou null quando um dos dois não foi resolvido —
cada ponto traz o próprio status.
Ponto → endereço
GET https://evodata.app/api/v1/mapa/reverso?lat=…&lon=…
curl "https://evodata.app/api/v1/mapa/reverso?lat=-23.5614&lon=-46.6559"
{
"dados": {
"municipio": { "nome": "São Paulo", "uf": "SP", "codigo_ibge": "3550308", "populacao": 11451999, "area_km2": 1531.22 },
"distrito": "Bela Vista",
"bairro": null,
"endereco_mais_proximo": { "logradouro": "Av. Paulista", "numero": "1578", "cep": "01310200", "distancia_m": 13 },
"cep_mais_proximo": { "cep": "01332040", "precisao": "logradouro", "distancia_m": 47,
"endereco": "Rua Professor Otávio Mendes, Bela Vista, São Paulo/SP" },
"lugar_mais_proximo": { "tipo": "suburb", "nome": "Jardim Paulista", "distancia_m": 609 }
}
}
Município, distrito e bairro vêm dos polígonos do OSM — bairro só onde a cidade tem os
limites mapeados. O endereço mais próximo vale até 150 m e o CEP até 400 m; além disso o
campo vem null, em vez de um palpite distante.
O que há perto
GET https://evodata.app/api/v1/mapa/proximos?cep=…&raio_km=…&categoria=…&tipo=…
curl "https://evodata.app/api/v1/mapa/proximos?cep=01310100&raio_km=0.5&tipo=pharmacy&limite=1"
{
"dados": {
"centro": { "cep": "01310100", "latitude": -23.5649616, "longitude": -46.6517717, /* … */ },
"raio_km": 0.5,
"pontos": [{
"osm": "node/3621336511", "categoria": "amenity", "tipo": "pharmacy", "rotulo": "Farmácia",
"nome": "Drogasil", "marca": "Drogasil", "cnpj": null,
"telefone": "+55 11 3286-0114;+55 11 3253-2501", "site": "https://www.drogasil.com.br/",
"horario": "Mo-Sa 07:00-23:00; Su 08:00-22:00",
"endereco": { "logradouro": "Avenida Paulista", "numero": "995", "cep": "01311100", /* … */ },
"latitude": -23.5654273, "longitude": -46.6520986, "distancia_m": 62
}],
"tem_mais": true
}
}
O ponto de referência é lat+lon, ponto=lat,lon ou
cep. Raio de até 50 km; até
200 itens, do mais perto ao mais longe.
categoria: amenity, shop, healthcare, office, tourism, leisure, craft, public_transport, railway, aeroway, emergency, historic.
tipo é o valor do OSM (pharmacy, supermarket,
fuel, school, bank…).
GET https://evodata.app/api/v1/mapa/entorno?cep=…&raio_km=…
Contagem por tipo num raio de até 10 km — "quantas farmácias, escolas e pontos de ônibus há a 1 km deste CEP". É a pergunta de análise de ponto comercial, numa chamada.
Empresas num raio
GET https://evodata.app/api/v1/mapa/empresas?cep=…&raio_km=…&divisao_cnae=…
curl "https://evodata.app/api/v1/mapa/empresas?cep=01310100&raio_km=0.5&divisao_cnae=56&limite=1"
{
"dados": {
"centro": { "cep": "01310100", /* … */ },
"raio_km": 0.5,
"empresas": [{
"cnpj": "…", "nome_exibicao": "…", "cnae": "Lanchonetes, casas de chá, de sucos e similares",
/* os mesmos campos da busca de empresas */
"distancia_m": 64,
"ponto": { "latitude": -23.5653, "longitude": -46.6522, "precisao": "numero", "raio_m": 517 }
}],
"ceps_no_raio": 111, "ceps_consultados": 100, "tem_mais": true, "incompleto": false
}
}
Estabelecimentos ativos da Receita perto do ponto, do mais perto ao mais longe.
A Receita não publica onde fica a porta: a posição é a do ponto do CEP de cada
empresa, e empresas do mesmo CEP aparecem à mesma distância. Por padrão só entram CEPs resolvidos
até a rua (precisao_minima=rua). Filtros: cnae (7 dígitos),
divisao_cnae (2 dígitos), nome, inclui_inativas. Raio de
até 10 km, até 200 empresas.
Ao contrário do resto do mapa, esta rota consulta a base da Receita, e fica no limitador
api — o mesmo de /empresas.
Endereço → ponto
GET https://evodata.app/api/v1/mapa/geocodificar?uf=…&cidade=…&logradouro=…&numero=…
curl "https://evodata.app/api/v1/mapa/geocodificar?uf=SP&cidade=São Paulo&logradouro=Av. Paulista&numero=1578"
{
"dados": {
"latitude": -23.5614968, "longitude": -46.6559649,
"precisao": "numero", "raio_m": 15,
"codigo_ibge": "3550308", "logradouro_encontrado": "Av. Paulista", "cep": null
}
}
Do mais fino ao mais grosso: numero (o número existe no OSM),
interpolado (entre os vizinhos de mesmo lado da rua), cep (o CEP
seccionado que cobre o número), logradouro (o meio da rua, com
homonimos quando há outra via de mesmo nome na cidade) e
municipio (a sede).
fonte.atribuicao: exiba-a junto do dado. fonte.dados_de é a data
do extrato carregado.
Erros
Respostas de erro trazem erro, um código estável seguro para
comparar em código, e quase sempre mensagem, texto em português
voltado a quem lê — sujeito a mudar de redação. Compare pelo
erro, nunca pela mensagem.
| HTTP | erro | Quando acontece |
|---|---|---|
422 |
filtros_ausentes |
GET /empresas sem nenhum filtro além do padrão de situação; /alteracoes sem alterado_desde nem cursor. |
422 |
data_invalida |
alterado_desde não é uma data ISO 8601. |
422 |
cursor_invalido |
O cursor não é o proximo_cursor de uma página anterior. |
422 |
anterior_ao_registro |
alterado_desde anterior a registro.inicio: o que mudou antes disso não está no registro. |
422 |
cursor_expirado |
Cursor mais antigo que o período guardado no registro de alterações. Refaça a carga completa. |
422 |
lote_vazio |
Endpoint de lote sem a lista no corpo (cnpjs, ids ou ceps). |
422 |
lote_excede_limite |
Mais de 100 itens num lote. |
422 |
cnpj_invalido |
O CNPJ não passa na validação dos dígitos verificadores. |
422 |
uf_invalida |
A sigla informada não está na tabela oficial, ou faltou em um endpoint que a exige. |
422 |
ip_invalido |
Não é um endereço IPv4 ou IPv6. |
422 |
ip_reservado |
IP de rede privada ou reservada (10.0.0.0/8, 192.168.0.0/16, ::1…): não tem localização pública. |
422 |
cep_invalido |
O CEP não tem 8 dígitos depois de retirada a pontuação (7 são completados com zero). |
404 |
nao_encontrado |
Identificador válido, mas ausente da base: CNPJ, pessoa, CEP ou localidade. |
429 |
— |
Limite de requisições excedido. Corpo padrão do Laravel; veja os cabeçalhos. |
503 |
consulta_expirada |
A combinação de filtros excedeu o tempo limite no banco. |
503 |
registro_indisponivel |
O registro de alterações do conjunto ainda não começou: a primeira comparação com a fonte não rodou. |
{
"erro": "filtros_ausentes",
"mensagem": "Informe ao menos um filtro. A base tem 72 milhões de estabelecimentos e uma consulta irrestrita não é atendida."
}
O 503 consulta_expirada merece tratamento próprio: ele não indica
indisponibilidade, e sim que aquela combinação de filtros é ampla
demais para o tempo limite do banco. Repetir a mesma chamada tende a falhar
de novo — o caminho é acrescentar um recorte mais estreito, como UF ou
município. Vale notar que a consulta expirada não fica em cache: se o cache
do PostgreSQL esquentar por outra via, a mesma chamada pode passar depois.
Enumerações
situacao
01 | Nula |
02 | Ativa |
03 | Suspensa |
04 | Inapta |
08 | Baixada |
porte
00 | Não informado |
01 | Microempresa |
03 | Empresa de pequeno porte |
05 | Demais |
matriz_filial
1 | Matriz |
2 | Filial |
ordenar
relevancia | Mais relevantes |
abertura_desc | Abertura mais recente |
abertura_asc | Abertura mais antiga |
capital_desc | Maior capital social |
razao_asc | Razão social (A–Z) |
buscar_em
razao | Razão social (padrão) |
fantasia | Nome fantasia |
ambos | Os dois campos |
size_class
micro | Microempresa |
pequena | Pequeno porte |
media | Médio porte |
grande | Grande porte |
uf
AC
AL
AP
AM
BA
CE
DF
ES
GO
MA
MT
MS
MG
PA
PB
PR
PE
PI
RJ
RN
RS
RO
RR
SC
SP
SE
TO
EX
EX designa estabelecimento sediado no exterior.
Limitações conhecidas
Nem tudo que a interface web faz está exposto por HTTP. Vale conhecer as fronteiras antes de desenhar a integração.
-
O CPF nunca sai em claro. Nenhum endpoint devolve o número
completo — busca, ficha e vínculos trazem sempre a forma mascarada
***.XXX.XXX-**. A busca por CPF exige os 11 dígitos, de modo que a API confirme uma identidade que você já tem, em vez de permitir descobri-las. - Não há exportação em massa. O teto é 100 itens por página, e a paginação profunda fica cara porque o banco precisa descartar tudo que veio antes. Para volumes grandes, use a exportação da interface, que percorre o conjunto por chave e não repete nem omite registros.
-
Não há ordenação garantida. Qualquer valor de
ordenarpode ser recusado em conjuntos grandes — a resposta continua200, com a explicação emavisos. Um cliente que dependa de ordem precisa checar esse array. -
Não há webhooks: a mudança é puxada, não empurrada. O que
mudou desde uma data sai em
/alteracoes, mas só a partir deregistro.iniciode cada conjunto, e como chaves — os dados vêm do/lote. Exclusão de CNPJ quase não aparece, porque a base não apaga empresa: a baixada vem como alteração. - Respostas são cacheadas. Buscas e fichas passam por cache de curta duração. Duas chamadas idênticas em sequência podem devolver exatamente o mesmo corpo mesmo que a base tenha mudado no meio.