This workflow follows the Execute Workflow Trigger → Postgres recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Tool: Salvar Cliente - Bellory",
"nodes": [
{
"parameters": {
"inputSource": "passthrough"
},
"id": "b1b2c3d4-1002-4002-a002-000000000001",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1,
"position": [
-600,
0
]
},
{
"parameters": {
"jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// TOOL: SALVAR CLIENTE (Cadastro R\u00e1pido)\n// Cadastra novo cliente via WhatsApp\n// Padr\u00e3o: clienteRapido = true\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst input = $input.item.json;\nconst query = input.query || '';\nconst organizacaoId = input.organizacao_id || input.organizacaoId;\nconst telefoneLimpo = input.telefone_limpo || input.telefone || '';\nconst remoteJid = input.remote_jid || input.remetente_numero || '';\n\n// Extrair nome do query\nlet nome = input.nome || '';\nif (!nome && query) {\n // O agente deve passar o nome no query\n nome = query.trim();\n}\n\n// Extrair telefone\nlet telefone = telefoneLimpo;\nif (!telefone && remoteJid) {\n telefone = remoteJid.replace('@s.whatsapp.net', '').replace('@c.us', '');\n}\n\nif (!nome) {\n return [{ json: { error: true, message: 'Nome do cliente n\u00e3o informado.' } }];\n}\nif (!telefone) {\n return [{ json: { error: true, message: 'Telefone do cliente n\u00e3o informado.' } }];\n}\nif (!organizacaoId) {\n return [{ json: { error: true, message: 'organizacao_id n\u00e3o informado.' } }];\n}\n\n// Gerar username e password no padr\u00e3o clienteRapido\nconst codigo6Digitos = String(Math.floor(100000 + Math.random() * 900000));\nconst username = 'cliente_rapido_' + codigo6Digitos;\nconst passwordPlain = 'cliente_rapido';\n\nreturn [{\n json: {\n nome: nome,\n telefone: telefone,\n organizacao_id: organizacaoId,\n username: username,\n password_plain: passwordPlain\n }\n}];"
},
"id": "b1b2c3d4-1002-4002-a002-000000000002",
"name": "Extrair Par\u00e2metros",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
-400,
0
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.error }}",
"value2": true
}
]
}
},
"id": "b1b2c3d4-1002-4002-a002-000000000003",
"name": "Tem Erro?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-200,
0
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT c.id FROM app.cliente c WHERE REGEXP_REPLACE(c.telefone, '[^0-9]', '', 'g') = REGEXP_REPLACE($1, '[^0-9]', '', 'g') AND c.organizacao_id = $2 LIMIT 1;",
"options": {
"queryReplacement": "={{ $json.telefone }},={{ $json.organizacao_id }}"
}
},
"id": "b1b2c3d4-1002-4002-a002-000000000004",
"name": "Verificar Duplicidade",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
0,
-64
],
"alwaysOutputData": true,
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Verificar se cliente j\u00e1 existe\nconst resultado = $input.item.json;\nconst dadosCliente = $('Extrair Par\u00e2metros').item.json;\n\nif (resultado && resultado.id) {\n return [{\n json: {\n duplicado: true,\n cliente_id: resultado.id,\n ...dadosCliente\n }\n }];\n}\n\nreturn [{\n json: {\n duplicado: false,\n ...dadosCliente\n }\n}];"
},
"id": "b1b2c3d4-1002-4002-a002-000000000005",
"name": "Verificar Resultado",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
200,
-64
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.duplicado }}",
"value2": true
}
]
}
},
"id": "b1b2c3d4-1002-4002-a002-000000000006",
"name": "J\u00e1 Existe?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
400,
-64
]
},
{
"parameters": {
"jsCode": "// Cliente j\u00e1 existe - retornar dados existentes\nconst dados = $input.item.json;\nreturn [{\n json: {\n response: JSON.stringify({\n sucesso: false,\n mensagem: 'Este telefone j\u00e1 est\u00e1 cadastrado.',\n cliente_id: dados.cliente_id\n }),\n success: false\n }\n}];"
},
"id": "b1b2c3d4-1002-4002-a002-000000000007",
"name": "Retornar Duplicado",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
600,
-128
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO app.cliente (organizacao_id, nome_completo, telefone, username, password, email, ativo, is_cadastro_incompleto, role, dt_criacao) VALUES ($1, $2, $3, $4, crypt($5, gen_salt('bf', 10)), NULL, true, true, 'ROLE_CLIENTE', NOW()) RETURNING id AS cliente_id, nome_completo AS nome;",
"options": {
"queryReplacement": "={{ $json.organizacao_id }},={{ $json.nome }},={{ $json.telefone }},={{ $json.username }},={{ $json.password_plain }}"
}
},
"id": "b1b2c3d4-1002-4002-a002-000000000008",
"name": "Inserir Cliente",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
600,
0
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Formatar resposta de sucesso\nconst resultado = $input.item.json;\n\nif (resultado && resultado.cliente_id) {\n return [{\n json: {\n response: JSON.stringify({\n sucesso: true,\n cliente_id: resultado.cliente_id,\n nome: resultado.nome,\n mensagem: 'Cliente cadastrado com sucesso!'\n }),\n success: true\n }\n }];\n} else {\n return [{\n json: {\n response: JSON.stringify({\n sucesso: false,\n mensagem: 'Erro ao cadastrar cliente. Tente novamente.'\n }),\n success: false\n }\n }];\n}"
},
"id": "b1b2c3d4-1002-4002-a002-000000000009",
"name": "Formatar Sucesso",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
800,
0
]
},
{
"parameters": {
"jsCode": "return [{ json: { response: $input.item.json.message, success: false } }];"
},
"id": "b1b2c3d4-1002-4002-a002-000000000010",
"name": "Retornar Erro",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
0,
96
]
}
],
"connections": {
"Execute Workflow Trigger": {
"main": [
[
{
"node": "Extrair Par\u00e2metros",
"type": "main",
"index": 0
}
]
]
},
"Extrair Par\u00e2metros": {
"main": [
[
{
"node": "Tem Erro?",
"type": "main",
"index": 0
}
]
]
},
"Tem Erro?": {
"main": [
[
{
"node": "Retornar Erro",
"type": "main",
"index": 0
}
],
[
{
"node": "Verificar Duplicidade",
"type": "main",
"index": 0
}
]
]
},
"Verificar Duplicidade": {
"main": [
[
{
"node": "Verificar Resultado",
"type": "main",
"index": 0
}
]
]
},
"Verificar Resultado": {
"main": [
[
{
"node": "J\u00e1 Existe?",
"type": "main",
"index": 0
}
]
]
},
"J\u00e1 Existe?": {
"main": [
[
{
"node": "Retornar Duplicado",
"type": "main",
"index": 0
}
],
[
{
"node": "Inserir Cliente",
"type": "main",
"index": 0
}
]
]
},
"Inserir Cliente": {
"main": [
[
{
"node": "Formatar Sucesso",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "Bellory"
},
{
"name": "Tool"
}
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Tool: Salvar Cliente - Bellory. Uses executeWorkflowTrigger, postgres. Event-driven trigger; 10 nodes.
Source: https://github.com/GuikBit/Bellory-back/blob/efcae38bb4114c036e0c8477aebe1850faae67e7/n8n-workflows/tool-salvar-cliente.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Agendamiento_v2. Uses n8n-nodes-evolution-api, redis, httpRequest, executeWorkflowTrigger. Event-driven trigger; 59 nodes.
Cancelacion_v2. Uses executeWorkflowTrigger, redis, httpRequest, n8n-nodes-evolution-api. Event-driven trigger; 46 nodes.
Youtube Searcher. Uses splitInBatches, httpRequest, manualTrigger, executeWorkflowTrigger. Event-driven trigger; 21 nodes.
QuepasaAutomatic. Uses postgres, executeWorkflowTrigger. Event-driven trigger; 20 nodes.
Log errors and avoid sending too many emails. Uses errorTrigger, postgres, stickyNote, emailSend. Event-driven trigger; 16 nodes.