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:

1. Formulário de registo e área de cliente

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.

2. CRM e back-office

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.

3. Verificar uma base de dados que já existe

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.

4. Ficha de código postal

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

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.

Experimentar a demoDocumentação da API