Moradas certas nos registos de clientes: área de cliente, CRM e back-office
Uma morada mal escrita num registo de cliente custa caro mais tarde: um envio devolvido, uma fatura com o código postal errado, o mesmo cliente duas vezes na base de dados. O Moradas sugere a rua enquanto se escreve, preenche o CP7, a localidade e o concelho, e verifica listas inteiras de moradas já guardadas. Grátis, sem chave de API, para moradas de Portugal.
Onde entra o Moradas
O checkout é só um dos sítios onde se escrevem moradas. Portais de cliente, CRM, fichas de fornecedores e ferramentas internas também as recebem — muitas vezes escritas à pressa por quem atende o telefone. Quatro cenários, do mais simples ao mais exigente:
O cliente começa a escrever a rua, escolhe a morada numa lista, e o código postal (CP7), a localidade e o concelho preenchem-se sozinhos — como no portal de cliente de um operador, onde a morada de faturação e a de instalação têm de bater certo. São duas linhas: carregar o widget e ligá-lo ao campo da morada.
<script src="https://moradas.dev/widget.js"></script>
<script>
PTAddress.attach(document.querySelector('#morada'), {
endpoint: 'https://moradas.dev',
fill: { postal: '#cp7', city: '#localidade', municipality: '#concelho' },
onSelect: function (data) {
// data = the suggestion's data object: street, localidade, concelho, distrito, cp7...
document.querySelector('#rua').value = data.street; // the street name as written in the data
}
});
</script>
Todos os campos continuam editáveis e, se o serviço não responder, o formulário funciona como um formulário normal. Numa rua com vários códigos postais, o widget preenche o CP7 exato quando o cliente escreve o número de porta. Todas as opções (fill, onSelect, onResolve, endpoint, lang…) estão na documentação do widget, com exemplos para React e Vue.
Quem regista moradas ao telefone não tem tempo para procurar códigos postais. O mesmo widget liga-se aos formulários do operador — o CRM de uma empresa de serviços, a ficha de cliente numa ferramenta interna — e o CP7 sai certo à primeira. Quando a rua tem vários códigos postais, o número de porta decide: o widget trata disso no browser; no servidor, /resolve faz o mesmo com o art_id da sugestão e o número.
GET /resolve?art=132467&numero=10 (art_id of "Rua das Adelas, Lisboa" in a fresh /suggest)
{ "resolved": { "value": "Rua das Adelas, Lisboa",
"data": { "art_id": 132467, "kind": "street", "street": "Rua das Adelas",
"localidade": "Lisboa", "concelho": "Lisboa", "distrito": "Lisboa",
"cp7": "1200-008", "nseg": 2 } },
"segments": [ { "cp7": "1200-007", "label": "Impares de 3 a 17A" },
{ "cp7": "1200-008", "label": "Pares de 2 a 28" } ] }
O art_id muda a cada atualização dos dados: use-o logo a seguir ao /suggest e não o guarde no registo — guarde a morada, o CP7 e a localidade. Sem número de porta, resolved vem null e segments lista os troços, para o operador escolher.
Uma base de clientes com anos de moradas escritas à mão tem códigos postais errados, localidades trocadas e registos repetidos. Com POST /batch passam-se até 100 moradas num só pedido — na prática, envie até 50 de cada vez — e cada linha volta com um veredicto: ok (código postal determinado, em cp7), ambiguous (sem resposta única: vários candidatos, uma rua com vários códigos sem número de porta, ou só uma localidade) ou not_found. As linhas ok corrigem-se sozinhas; as ambiguous vêm com a melhor candidata, para alguém decidir. Serve também para verificações de conformidade: confirmar que a morada declarada num registo existe e tem aquele código postal.
curl -s -X POST "https://moradas.dev/batch" -H "Content-Type: application/json" \
-d '{"items":[{"id":"o-1001","q":"Avenida da Liberdade 196, Lisboa"},
{"id":"o-1003","q":"xyzxyz qqq"}]}'
# {"results":[{"id":"o-1001","q":"Avenida da Liberdade 196, Lisboa","status":"ok",
# "cp7":"1250-147","suggestion":{…}},
# {"id":"o-1003","q":"xyzxyz qqq","status":"not_found",
# "cp7":null,"suggestion":null}]}
id é o seu identificador do registo, devolvido tal e qual. Um pedido com N moradas conta como N pedidos no limite geral; num 429, espere os segundos do cabeçalho Retry-After e continue. O exemplo completo em Python e os pormenores dos veredictos estão na documentação do /batch.
Muitos registos já têm um código postal, mas não a localidade, o concelho ou o distrito — ou têm-nos errados. /cp/{cp7} devolve a ficha do código: localidade, concelho, distrito e as ruas que abrange. Com só os quatro primeiros dígitos, /cp/{cp4} lista todos os códigos dessa zona — útil para validar um campo ou preencher uma lista de escolha.
GET /cp/1000-098
{ "cp7": "1000-098", "cp4": "1000", "cp3": "098",
"distrito": "Lisboa", "concelho": "Lisboa", "localidade": "Lisboa",
"arterias": [ { "art_id": 130446, "street": "Praça do Chile",
"troco": null, "porta": null, "cliente": null } ] }
Valide o formato antes de chamar (^\d{4}-\d{3}$); um código inexistente devolve 404 com o motivo no cabeçalho X-Moradas-Hint. Mais em Validar código postal.
Porque funciona para registos
- Sem chave, sem conta. Grátis, incluindo uso comercial. Copie o exemplo e corra-o.
- CORS aberto. O browser do cliente ou do operador chama o serviço diretamente; não precisa de um proxy no seu servidor.
- Contrato estável (v1). Os campos nunca são renomeados nem removidos, apenas acrescentados — uma integração num CRM não parte com uma atualização.
- Privacidade. Sem cookies, sem contas. O texto pesquisado é processado apenas para responder ao pedido: não é guardado nem associado a uma pessoa; guardamos só contagens agregadas de utilização. Pormenores na página de privacidade.
- Limites. Cerca de 50 pedidos por 10 segundos por IP;
/cptem um limite próprio, mais folgado. Acima disso, 429 comRetry-After. Sem garantia de disponibilidade — guarde em cache o que precisar.
Perguntas frequentes
Posso usar no back-office, sem browser?
Sim. A API REST serve a partir de qualquer linguagem no servidor — há exemplos prontos a copiar em curl, JavaScript, PHP, Python e C# no início rápido, e POST /batch para listas. O widget é só uma das formas de a usar.
E o RGPD?
O Moradas não usa cookies nem contas e não guarda o texto pesquisado: a morada é processada apenas para responder ao pedido e não fica associada a uma pessoa. Guardamos contagens agregadas por hora (endpoint, domínio do site de origem, tipo de cliente, país, estado da resposta) — nada que identifique alguém. Pode remeter para a página de privacidade na sua própria política.
Com que frequência são atualizados os dados?
Semanalmente, com uma verificação automática antes de cada atualização. O art_id das sugestões muda nessa altura — guarde a morada e o CP7, nunca o art_id.
O que acontece se o serviço não responder?
No widget, a lista avisa que o serviço está temporariamente indisponível e o formulário continua a funcionar normalmente. Na API, trate o 429 e as falhas como em qualquer serviço externo: espere o Retry-After e repita, e guarde em cache o que precisar. O estado atual e o registo de alterações estão na página Estado.