EvoDATA

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.

Baixar OpenAPI 3.1

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 basehttps://evodata.app/api/v1
ProtocoloHTTPS obrigatório. Chamadas em HTTP recebem redirecionamento permanente.
Formatoapplication/json, codificado em UTF-8. Acentos saem escapados como \uXXXX, que é JSON válido.
MétodosGET, e POST nos endpoints de lote, que recebem a lista no corpo. A API é de leitura.
Versãov1. 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:

RecursosAcesso
/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.

Quem tem direito. A API de pessoas exige conta de administrador ou plano Essencial, Profissional ou Corporativo. O plano gratuito recebe 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

HTTPerroSignificado
401credencial_ausenteNenhuma chave foi enviada.
401credencial_invalidaChave inexistente, revogada ou expirada. Os três casos respondem igual, para não confirmar que uma chave já existiu.
403plano_sem_apiChave 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çãoLimiteChave
Empresas, referências e pessoas1000 req/minID da conta
/ceps, /localidades, /ips, /mapa, /produtos1000 req/minID 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-LimitTeto da janela corrente.
X-RateLimit-RemainingQuanto resta antes do bloqueio.
Retry-AfterSegundos 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.
Para manter uma cópia em dia, não refaça a busca inteira: pegue só o que mudou em GET /empresas/alteracoes?alterado_desde=….

Parâmetros

Identificação

ParâmetroTipoDescriçãoExemplo
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âmetroTipoDescriçãoExemplo
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âmetroTipoDescriçãoExemplo
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âmetroTipoDescriçãoExemplo
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âmetroTipoDescriçãoExemplo
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âmetroTipoDescriçãoExemplo
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âmetroTipoDescriçãoExemplo
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

CampoTipoDescriçã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.
Campos marcados Enriquecimento ou Google Places não vêm da Receita Federal e existem apenas para parte da base. Espere 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:

CampoTipoDescriçã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
}
O 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.

Para manter uma cópia em dia, não refaça a busca: pegue só o que mudou em GET /pessoas/alteracoes?alterado_desde=….

Parâmetros

ParâmetroTipoDescriçãoExemplo
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
Dois filtros são recusados de propósito, com 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:

BlocoTipoConteú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.
O CPF dos vínculos aparece em duas formas: ***.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:

tipoO que éCampos próprios
logradouroRua, avenida, praça — 97% dos CEPs.tipo_logradouro, logradouro, numeracao
localidadeCEP ú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_operacionalAgência ou unidade dos Correios.nome, endereco, caixas_postais
caixa_postal_comunitariaCaixa postal comunitária.nome, endereco, caixas_postais
especialCEP 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.
Para manter uma cópia em dia, não reconsulte os 1,57 milhão de CEPs: pegue só o que mudou em 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

CampoTipoDescriçã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âmetroTipoDescriçãoExemplo
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 }
}
Não há paginação: 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" },
      /* … */
    }
  ]
}
CampoTipoDescriçã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)" }
}
Os dados vêm do eDNE em vigor na última importação; os Correios o atualizam periodicamente, e um CEP criado depois só aparece na importação seguinte. O eDNE não traz coordenadas: as de 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

ConjuntoChave na listaRegistro desdeDados 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âmetroTipoDescriçãoExemplo
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"
}
CampoTipoDescriçã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.
ConjuntoPartesQuando 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

  1. Carga inicial pela consulta completa (busca, exportação ou lote). Anote quando ela começou.
  2. Primeira sincronização com alterado_desde = essa data. Se a sua carga é anterior a registro.inicio, use registro.inicio — o que mudou entre as duas não está no registro.
  3. Siga proximo_cursor até tem_mais ser false, e guarde o último cursor.
  4. Nas próximas, só o cursor guardado: continua exatamente de onde parou, sem repetir nem pular, mesmo que uma comparação nova tenha sido publicada no meio.
  5. Para cada chave, busque os dados no /lote do conjunto e grave por cima (upsert) — ou apague, em exclusao. 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
Trate cada linha como "busque de novo". A mesma chave pode voltar em comparações seguintes, e uma página pode ser entregue duas vezes se a sua gravação cair no meio. Com upsert por chave, repetir é inofensivo.
Antes de 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.

A localização é da rede, não da pessoa. O IP diz onde o provedor registra aquele bloco de endereços. As coordenadas são um ponto dentro de um círculo de 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."
  }
}
CampoTipoDescriçã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": { /* … */ }
}
This product includes GeoLite2 Data created by MaxMind, available from https://www.maxmind.com. A base é trocada inteira a cada release da MaxMind, e o campo 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:

precisaoComo o ponto foi achado
numeroEndereços do OSM na mesma rua, dentro da faixa de numeração do CEP
cepObjetos e vias do OSM marcados com este CEP
logradouroA rua do CEP, encontrada no OSM pelo nome
logradouro_similarRua de mesmo nome com outro tipo (ex.: Travessa × Rua) — confira
bairroCentro do bairro
localidadeDistrito ou povoado
municipioSede do município
Duas distâncias, e cada uma diz o que é. 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).

© colaboradores do OpenStreetMap, dados sob a licença ODbL. Toda resposta traz 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.

HTTPerroQuando 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

01Nula
02Ativa
03Suspensa
04Inapta
08Baixada

porte

00Não informado
01Microempresa
03Empresa de pequeno porte
05Demais

matriz_filial

1Matriz
2Filial

ordenar

relevanciaMais relevantes
abertura_descAbertura mais recente
abertura_ascAbertura mais antiga
capital_descMaior capital social
razao_ascRazão social (A–Z)

buscar_em

razaoRazão social (padrão)
fantasiaNome fantasia
ambosOs dois campos

size_class

microMicroempresa
pequenaPequeno porte
mediaMédio porte
grandeGrande 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 ordenar pode ser recusado em conjuntos grandes — a resposta continua 200, com a explicação em avisos. 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 de registro.inicio de 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.

Toda chamada é registrada na trilha de auditoria com origem, IP, alvo e volume de resultados, conforme descrito na política de privacidade.