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": "OTTO - \u00c9pico 3: Motor de Tempo Psicol\u00f3gico",
"nodes": [
{
"parameters": {
"content": "## \u23f1\ufe0f \u00c9pico 3: Motor de Tempo Psicol\u00f3gico\n\n**Regra**: Modelar comportamento de compra, n\u00e3o hor\u00e1rio administrativo.\n\n\ud83d\udd25 Lead Quente (Proposta na mesa): tempo real 24/7\n- Alerta amarelo pode cair no s\u00e1bado\n\u2744\ufe0f Lead Frio (Qualifica\u00e7\u00e3o): business hours\n- Pausa sex 18h, volta seg 08h\n\n**Cronjob**: Verifica cron\u00f4metros ativos onde\nstate_version = version atual do lead",
"height": 280,
"width": 420,
"color": 6
},
"id": "note-docs",
"name": "\ud83d\udccb Documenta\u00e7\u00e3o",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
40,
40
]
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"id": "cron-trigger",
"name": "Cronjob: Verificar Cron\u00f4metros (15min)",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
260,
340
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT c.id as cronometro_id, c.lead_id, c.lead_state_version, c.alerta_amarelo_at, c.transbordo_vermelho_at, c.temperatura_no_inicio, c.tipo_sla, c.alerta_amarelo_enviado, c.alerta_vermelho_enviado, l.nome_cliente, l.veiculo_interesse, l.estagio_atual, l.temperatura, l.state_version as lead_state_version_atual, l.vendedor_id, l.metadata, v.nome as vendedor_nome, v.whatsapp_id as vendedor_whatsapp FROM cronometros_otto c INNER JOIN leads l ON l.id = c.lead_id INNER JOIN vendedores v ON v.id = l.vendedor_id WHERE c.status_cronometro = 'ativo' AND c.lead_state_version = l.state_version AND (c.alerta_amarelo_at <= NOW() OR c.transbordo_vermelho_at <= NOW()) AND (c.alerta_amarelo_enviado = FALSE OR c.alerta_vermelho_enviado = FALSE) ORDER BY c.alerta_amarelo_at ASC LIMIT 50;",
"options": {}
},
"id": "buscar-cronometros",
"name": "Buscar Cron\u00f4metros Ativos (Vers\u00e3o Validada)",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
500,
340
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "has-results",
"leftValue": "={{ $json.cronometro_id }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
}
},
"id": "if-tem-alertas",
"name": "Tem Alertas Pendentes?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
740,
340
]
},
{
"parameters": {
"jsCode": "// ALGORITMO DE DEGRADA\u00c7\u00c3O DE SLA (Tempo Psicol\u00f3gico)\nconst items = $input.all();\nconst agora = new Date();\nconst results = [];\n\nfor (const item of items) {\n const d = item.json;\n const temp = (d.temperatura || d.temperatura_no_inicio || '').toLowerCase();\n \n // Determinar tipo de SLA baseado em temperatura\n let tipoSLA = 'business_hours'; // padr\u00e3o\n const ESTAGIOS_QUENTES = ['PROPOSTA', 'NEGOCIACAO', 'APROVACAO_FINANCEIRA', 'FECHAMENTO'];\n \n if (temp === 'quente' || temp === 'hot' || ESTAGIOS_QUENTES.includes(d.estagio_atual)) {\n tipoSLA = 'real_time'; // \ud83d\udd25 Lead quente: tempo real 24/7\n }\n \n // Verificar se est\u00e1 em business hours (para leads frios)\n const hora = agora.getHours();\n const diaSemana = agora.getDay(); // 0=dom, 6=sab\n const emHorarioComercial = diaSemana >= 1 && diaSemana <= 5 && hora >= 8 && hora < 18;\n \n // Se lead frio e fora do hor\u00e1rio comercial, pular\n if (tipoSLA === 'business_hours' && !emHorarioComercial) {\n continue;\n }\n \n // Determinar zona do alerta\n const alertaAmareloAt = new Date(d.alerta_amarelo_at);\n const transbordoAt = new Date(d.transbordo_vermelho_at);\n \n let zona = 'VERDE';\n let tipo_alerta = null;\n \n if (transbordoAt <= agora && !d.alerta_vermelho_enviado) {\n zona = 'VERMELHA';\n tipo_alerta = 'transbordo';\n } else if (alertaAmareloAt <= agora && !d.alerta_amarelo_enviado) {\n zona = 'AMARELA';\n tipo_alerta = 'nudge';\n }\n \n if (tipo_alerta) {\n // Calcular tempo decorrido\n const horasDecorridas = Math.round((agora - alertaAmareloAt) / (1000 * 60 * 60));\n \n // Buscar \u00faltima obje\u00e7\u00e3o do metadata\n let ultimaObjecao = null;\n try {\n const meta = typeof d.metadata === 'string' ? JSON.parse(d.metadata) : d.metadata;\n ultimaObjecao = meta?.ultima_objecao || meta?.objecao || null;\n } catch(e) {}\n \n results.push({ json: {\n ...d,\n zona,\n tipo_alerta,\n tipo_sla: tipoSLA,\n horas_decorridas: horasDecorridas,\n ultima_objecao: ultimaObjecao,\n em_horario_comercial: emHorarioComercial\n }});\n }\n}\n\nreturn results.length > 0 ? results : [{ json: { sem_alertas: true } }];"
},
"id": "calcular-sla",
"name": "Calcular Degrada\u00e7\u00e3o SLA",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
980,
240
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "is-amarelo",
"leftValue": "={{ $json.zona }}",
"rightValue": "AMARELA",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputLabel": "\ud83d\udfe1 Zona Amarela (Nudge)"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "is-vermelho",
"leftValue": "={{ $json.zona }}",
"rightValue": "VERMELHA",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputLabel": "\ud83d\udd34 Zona Vermelha (Transbordo)"
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"id": "switch-zona",
"name": "Classificar Zona",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
1220,
240
]
}
],
"connections": {
"Cronjob: Verificar Cron\u00f4metros (15min)": {
"main": [
[
{
"node": "Buscar Cron\u00f4metros Ativos (Vers\u00e3o Validada)",
"type": "main",
"index": 0
}
]
]
},
"Buscar Cron\u00f4metros Ativos (Vers\u00e3o Validada)": {
"main": [
[
{
"node": "Tem Alertas Pendentes?",
"type": "main",
"index": 0
}
]
]
},
"Tem Alertas Pendentes?": {
"main": [
[
{
"node": "Calcular Degrada\u00e7\u00e3o SLA",
"type": "main",
"index": 0
}
],
[]
]
},
"Calcular Degrada\u00e7\u00e3o SLA": {
"main": [
[
{
"node": "Classificar Zona",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"id": "otto-1",
"name": "OTTO"
},
{
"id": "otto-6",
"name": "Tempo"
},
{
"id": "otto-7",
"name": "\u00c9pico 3"
}
],
"triggerCount": 1,
"updatedAt": "2026-02-26T12:00:00.000Z",
"versionId": "1"
}
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
OTTO - Épico 3: Motor de Tempo Psicológico. Uses postgres. Scheduled trigger; 6 nodes.
Source: https://github.com/paraisolorrayne/Attra/blob/abb8ae4ce8cb0a2a566239a254c12a2d03e7d08e/automations/epico-3-motor-tempo-psicologico.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.
Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.
공유회_알림톡_크론. Uses postgres, httpRequest, n8n-nodes-solapi. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.