🌐 Validação Externa de Cadastro de Cliente
📋 Visão Geral
O módulo de validação externa de cliente permite integrar um serviço externo ao fluxo de cadastro e atualização de clientes, habilitando regras de negócio personalizadas como políticas antifraude, validações fiscais ou restrições específicas do negócio.
A validação é executada de forma síncrona (hard-fail) — se o serviço externo rejeitar a operação, o cadastro ou atualização é bloqueado e o erro é propagado para o consumidor da API.
| Operação | Ação | Descrição |
|---|---|---|
| Cadastro 🆕 | create | Chamada antes da criação de um novo cliente |
| Atualização ✏️ | update | Chamada antes da atualização de um cliente existente |
---
🔄 Fluxo de Execução
1. O payload do cliente é sanitizado (campo password é removido antes do envio)
2. A URL do serviço externo é carregada a partir do setting customers/validation/external-url
3. O serviço externo é chamado via POST com o payload completo do cliente
4. ✅ Se aprovado (status: ok): o fluxo de cadastro/atualização continua normalmente
5. ❌ Se rejeitado (HTTP 4xx): a operação é bloqueada e o erro é propagado
6. 📝 Em caso de falha, um log técnico é persistido para auditoria
---
📤 Contrato de Requisição
O serviço externo recebe um POST com o seguinte payload:
Exemplo para operação create
1{2 "operation": "create",3 "domain": "sua-loja.com.br",4 "customer": {5 "email": "joao.silva@email.com.br",6 "nameCorporateName": "João Silva",7 "tradeName": "João Silva",8 "isCorporate": false,9 "gender": "M",10 "nationality": "brasileiro",11 "birthdate": "1990-01-15",12 "phone": "+5511987654321",13 "origin": "frontend",14 "documents": [15 {16 "type": "cpf",17 "document": "123.456.789-00"18 }19 ],20 "active": true,21 "additionalFields": [22 {23 "code": "inscricao-estadual",24 "value": "123456789"25 }26 ]27 }28}Exemplo para operação update
Na atualização, o payload é o merge entre os dados atuais do cliente e os novos dados enviados. Isso significa que campos não alterados também estarão presentes:
1{2 "operation": "update",3 "domain": "sua-loja.com.br",4 "customer": {5 "id": 789,6 "salesChannelId": 1,7 "tradePolicyId": 1,8 "email": "joao.silva@email.com.br",9 "dealerGroupId": null,10 "nameCorporateName": "João Silva",11 "tradeName": "João Silva",12 "isCorporate": false,13 "gender": "M",14 "nationality": "brasileiro",15 "birthdate": "1990-01-15",16 "phone": "+5511987654321",17 "walletAmount": 0,18 "pointSystemAmount": 0,19 "orderQuantity": 5,20 "cancelledOrderQuantity": 0,21 "orderValue": 1250.00,22 "lastOrder": null,23 "origin": "frontend",24 "createdAt": "2025-06-10 14:30:00",25 "active": true,26 "deleted": false,27 "masked": false,28 "addresses": [29 {30 "id": 123,31 "zipCode": "01001-000",32 "recipient": "João Silva",33 "street": "Praça da Sé",34 "number": "100",35 "district": "Sé",36 "city": "São Paulo",37 "state": "São Paulo",38 "stateCode": "SP",39 "countryCode": "BRA",40 "complement": "Apto 1"41 }42 ],43 "documents": [44 {45 "type": "cpf",46 "document": "123.456.789-00"47 }48 ],49 "flags": null,50 "additionalFields": [51 {52 "code": "inscricao-estadual",53 "value": "123456789"54 }55 ]56 }57}📊 Campos do payload
| Campo | Tipo | Presente em | Descrição | |
|---|---|---|---|---|
operation | string | ambos | Operação: create ou update | |
domain | string | ambos | Domínio do canal de venda | |
customer.email | string | ambos | E-mail do cliente | |
customer.nameCorporateName | string | ambos | Nome ou razão social | |
customer.tradeName | string | ambos | Sobrenome ou nome fantasia | |
customer.isCorporate | boolean | ambos | Indica se é pessoa jurídica | |
customer.gender | string | ambos | Gênero: male, female, undefined | |
customer.nationality | string | ambos | Nacionalidade | |
customer.birthdate | string | ambos | Data de nascimento (YYYY-MM-DD) | |
customer.phone | string | ambos | Telefone com DDI | |
customer.origin | string | ambos | Origem do cadastro (frontend, admin, etc) | |
customer.documents | array | ambos | Lista de documentos do cliente | |
customer.documents.*.type | string | ambos | Tipo do documento (cpf, cnpj, rg, ie) | |
customer.documents.*.document | string | ambos | Número do documento | |
customer.active | boolean | ambos | Status de ativação | |
customer.additionalFields | array | ambos | Campos adicionais personalizados | |
customer.additionalFields.*.code | string | ambos | Código do campo adicional | |
customer.additionalFields.*.value | mixed | ambos | Valor do campo adicional | |
customer.id | integer | update | ID do cliente | |
customer.salesChannelId | integer | update | Canal de venda de origem | |
customer.tradePolicyId | integer | update | Política comercial | |
customer.dealerGroupId | integer | update | ID do grupo de revendedor | |
customer.walletAmount | number | update | Saldo da carteira | |
customer.pointSystemAmount | number | update | Saldo do sistema de pontos | |
customer.orderQuantity | number | update | Quantidade de pedidos | |
customer.cancelledOrderQuantity | number | update | Quantidade de pedidos cancelados | |
customer.orderValue | number | update | Valor total dos pedidos | |
customer.lastOrder | object\ | null | update | Último pedido do cliente |
customer.createdAt | string | update | Data de cadastro | |
customer.deleted | boolean | update | Se o cliente foi excluído | |
customer.masked | boolean | update | Se os dados estão mascarados | |
customer.addresses | array\ | null | update | Endereços do cliente |
customer.flags | object\ | null | update | Flags do cliente |
password é automaticamente removido do payload antes do envio ao serviço externo.---
✅ Contrato de Resposta — Sucesso
1{2 "status": "ok"3}O serviço deve retornar HTTP 200 com "status": "ok" para aprovar a operação.
---
❌ Contrato de Resposta — Rejeição de Negócio
1{2 "error": "Cadastro reprovado por política antifraude."3}O serviço deve retornar HTTP 4xx (recomendado 422) com ao menos um dos seguintes campos de mensagem:
| Campo | Obrigatório | Descrição | ||
|---|---|---|---|---|
error \ | message \ | errorMessage | ✅ Sim (ao menos um) | Mensagem descritiva do erro que será propagada ao consumidor da API |
UAPPI_STORE_CUSTOMER_EXTERNAL_VALIDATION_REJECTED com a mensagem extraída da resposta do serviço externo.---
⚠️ Erros de Infraestrutura Externa
Falhas de comunicação são tratadas como hard-fail e bloqueiam a operação:
| Código Interno | HTTP | Cenário |
|---|---|---|
UAPPI_STORE_CUSTOMER_EXTERNAL_VALIDATION_TIMEOUT | 504 | O serviço não respondeu no tempo limite (5s) |
UAPPI_STORE_CUSTOMER_EXTERNAL_VALIDATION_UNAVAILABLE | 502 | Erro de conexão ou erro 5xx no serviço |
UAPPI_STORE_CUSTOMER_EXTERNAL_VALIDATION_INVALID_CONTRACT | 502 | HTTP 200 mas o corpo não contém "status": "ok" |
UAPPI_STORE_CUSTOMER_EXTERNAL_VALIDATION_REJECTED | 422 | O serviço rejeitou a operação (HTTP 4xx) |
📝 Logs de Auditoria
Todas as chamadas que resultam em falha são registradas na tabela customer_external_validation_log com:
| Campo | Descrição |
|---|---|
customer_id | ID do cliente (quando disponível) |
trade_policy_id | Política comercial |
sales_channel_id | Canal de venda |
operation | Operação: create ou update |
url | URL chamada |
http_status | Código HTTP retornado |
request_time_ms | Tempo de resposta em milissegundos |
request | Payload enviado (dados sensíveis mascarados) |
response | Corpo da resposta |
error_type | Classificação: connection, server, timeout, business, contract |
🔒 Mascaramento de Dados
Os seguintes campos são mascarados antes da persistência do log:
customer.tradeNameecustomer.nameCorporateName— nome mascaradocustomer.email— e-mail mascarado (ex:cl*@exemplo.com)customer.phone— telefone mascarado (ex:+5578)customer.documents..document— documento mascarado (ex:..-)- Deve aceitar requisições
POSTcomContent-Type: application/json - Deve responder em até 5 segundos (timeout de conexão e resposta)
- Deve retornar
Content-Type: application/json - Deve retornar
{"status": "ok"}para aprovar ou HTTP 4xx para rejeitar - A validação opera em modo hard-fail: qualquer falha bloqueia o cadastro ou a atualização do cliente
- O campo
passwordé sempre removido do payload antes do envio ao serviço externo - A mesma URL de serviço é utilizada para ambas as operações (create e update), diferenciadas pelo campo
operationno payload - Os logs são persistidos apenas para chamadas com falha — operações aprovadas não geram registro de log
- O serviço externo recebe o payload completo do cliente, incluindo documentos e endereços, permitindo validações complexas
---
⚙️ Configuração
| Setting | Descrição |
|---|---|
customers/validation/external-url | Endpoint completo para validação externa de cliente (create/update) |
📌 Requisitos do Serviço Externo
---
🔗 Endpoints Relacionados
| Endpoint | Descrição |
|---|---|
POST /customers | Cadastro de cliente (dispara validação com operation: create) |
PUT /customers/{customerId} | Atualização de cliente (dispara validação com operation: update) |
POST /customer | Cadastro de cliente via API pública (dispara validação com operation: create) |
PUT /customer | Atualização de cliente via API pública (dispara validação com operation: update) |
GET /customers/external-validation-logs | Listagem de logs técnicos de validação externa |
📌 Notas e Considerações
Listagem de Logs de Validação Externa de Cliente
/customers/external-validation-logs
Endpoint responsável por listar logs técnicos de validação externa de cliente
Descrição
Retorna uma listagem paginada dos logs técnicos gerados quando a validação externa de cliente falha.
O endpoint é voltado ao painel administrativo e permite auditoria operacional por operação (create ou update), tipo de erro, status HTTP retornado pelo provedor externo e tempo de resposta.
Parâmetros
Headers Obrigatórios
| Header | Valor | Descrição |
|---|---|---|
Authorization | Bearer {token} | Token de autenticação de usuário |
Campos de Condição Disponíveis
| Campo | Tipo | Descrição |
|---|---|---|
id | integer | Filtrar pelo ID do log |
tradePolicyId | integer | Filtrar pela política comercial |
salesChannelId | integer | Filtrar pelo canal de venda |
url | string | Filtrar pela URL chamada no provedor externo |
operation | string | Filtrar por operação (create ou update) |
errorType | string | Filtrar por tipo de erro (contract, connection, timeout, business, server) |
httpStatus | integer | Filtrar pelo status HTTP retornado pelo provedor externo |
requestTimeMs | integer | Filtrar pelo tempo de resposta em milissegundos |
request | string | Filtrar pelo payload registrado |
response | string | Filtrar pela resposta registrada |
createdAt | string | Filtrar pela data de criação do log |
Campos de Ordenação Disponíveis
| Campo | Descrição |
|---|---|
id | Ordenar pelo ID do log |
operation | Ordenar pela operação |
errorType | Ordenar pelo tipo de erro |
httpStatus | Ordenar pelo status HTTP |
requestTimeMs | Ordenar pelo tempo de resposta |
createdAt | Ordenar pela data de criação |
Exemplo de Requisição
1curl --request GET \2 --url '{{MAIN_URL}}/customers/external-validation-logs?limit=20&offset=0&condition[operation]=create&order[0][field]=createdAt&order[0][direction]=desc' \3 --header 'Authorization: Bearer SEU_TOKEN_AQUI'✅ Resposta de Sucesso
HTTP Status: 200 OK
1{2 "status": true,3 "data": {4 "registers": [5 {6 "id": 19,7 "customerId": null,8 "tradePolicyId": 1,9 "salesChannelId": 1,10 "operation": "create",11 "url": "https://validator.exemplo.com/customers/validate",12 "errorType": "business",13 "httpStatus": 422,14 "requestTimeMs": 241,15 "request": {16 "operation": "create",17 "domain": "loja.exemplo.com.br",18 "customer": {19 "id": null,20 "email": "cl<em></em>*@exemplo.com",21 "nameCorporateName": "J<strong><em> S</strong></em>",22 "phone": "+55<strong></strong><strong></strong>78",23 "documents": [24 {25 "type": "cpf",26 "document": "<strong><em>.</strong></em>.<strong>*-</strong>"27 }28 ]29 }30 },31 "response": {32 "status": "error",33 "message": "Cadastro reprovado por política antifraude."34 },35 "createdAt": "2026-04-15 16:04:30"36 }37 ],38 "pagination": {39 "limit": 20,40 "offset": 0,41 "pages": 1,42 "registers": 143 }44 }45}⚠️ Possíveis erros:
| Código Interno | Código HTTP | Descrição |
|---|---|---|
| Sem código interno específico | 401 | Token ausente, inválido ou expirado |
| Sem código interno específico | 403 | Usuário autenticado sem escopo CUSTOMER_READ |