AutomationFlowsAI & RAG › Lua Nova - Sistema Completo

Lua Nova - Sistema Completo

Lua Nova - Sistema Completo. Uses postgres, httpRequest, openAi. Webhook trigger; 55 nodes.

Webhook trigger★★★★★ complexityAI-powered55 nodesPostgresHTTP RequestOpenAI
AI & RAG Trigger: Webhook Nodes: 55 Complexity: ★★★★★ AI nodes: yes Added:

This workflow follows the HTTP Request → OpenAI 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 →

Download .json
{
  "name": "Lua Nova - Sistema Completo",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "lua-nova-webhook",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "webhook-principal",
      "name": "Webhook - Receber Mensagem",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1.1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "telefone",
              "name": "telefone",
              "value": "={{ $json.body.data.key.remoteJid.replace('@s.whatsapp.net', '') }}",
              "type": "string"
            },
            {
              "id": "mensagem_texto",
              "name": "mensagem_texto",
              "value": "={{ $json.body.data.message?.conversation || $json.body.data.message?.extendedTextMessage?.text || '' }}",
              "type": "string"
            },
            {
              "id": "tipo_mensagem",
              "name": "tipo_mensagem",
              "value": "={{ $json.body.data.message?.audioMessage ? 'audio' : $json.body.data.message?.imageMessage ? 'imagem' : 'texto' }}",
              "type": "string"
            },
            {
              "id": "messageId",
              "name": "messageId",
              "value": "={{ $json.body.data.key.id }}",
              "type": "string"
            },
            {
              "id": "timestamp_mensagem",
              "name": "timestamp_mensagem",
              "value": "={{ $json.body.data.messageTimestamp }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "extrair-dados-webhook",
      "name": "Extrair - Dados do Webhook",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT * FROM clientes WHERE telefone = $1",
        "options": {
          "queryReplacement": "={{ $json.telefone }}"
        }
      },
      "id": "buscar-cliente",
      "name": "DB - Buscar Cliente",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        680,
        300
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cliente-existe",
              "leftValue": "={{ $json.id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "exists"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "switch-cliente-existe",
      "name": "Switch - Cliente Existe?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO clientes (telefone, assistente_atual, fase_atual, status_atendimento, ultima_interacao) VALUES ($1, 'luana', 'inicial', 'ativo', NOW()) RETURNING *",
        "options": {
          "queryReplacement": "={{ $('Extrair - Dados do Webhook').item.json.telefone }}"
        }
      },
      "id": "criar-cliente",
      "name": "DB - Criar Novo Cliente",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        1120,
        420
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE clientes SET ultima_interacao = NOW() WHERE telefone = $1 RETURNING *",
        "options": {
          "queryReplacement": "={{ $('Extrair - Dados do Webhook').item.json.telefone }}"
        }
      },
      "id": "atualizar-cliente",
      "name": "DB - Atualizar \u00daltima Intera\u00e7\u00e3o",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        1120,
        180
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const clienteNovo = $input.item(0).json;\nconst clienteExistente = $input.item(1).json;\n\nconst cliente = clienteExistente.id ? clienteExistente : clienteNovo;\n\nreturn {\n  json: {\n    ...cliente,\n    telefone: cliente.telefone,\n    nome: cliente.nome || '',\n    assistente_atual: cliente.assistente_atual || 'luana',\n    fase_atual: cliente.fase_atual || 'inicial',\n    status_atendimento: cliente.status_atendimento || 'ativo',\n    cliente_bloqueado: cliente.cliente_bloqueado || false\n  }\n};"
      },
      "id": "unificar-cliente",
      "name": "Code - Unificar Dados Cliente",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cliente-bloqueado",
              "leftValue": "={{ $json.cliente_bloqueado }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "switch-cliente-bloqueado",
      "name": "Switch - Cliente Bloqueado?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1560,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "mensagem_bloqueio",
              "name": "mensagem_final",
              "value": "={{ $json.assistente_atual === 'luana' ? '**Luana**\\n\\nOi! Notei que voc\u00ea j\u00e1 entrou em contato recentemente. Para garantir um atendimento de qualidade para todos, pe\u00e7o que aguarde um pouquinho antes de enviar novas mensagens. Estou aqui quando voc\u00ea precisar! \ud83c\udf19\u2728' : $json.assistente_atual === 'camila' ? '**Camila**\\n\\nOl\u00e1! Percebi que voc\u00ea j\u00e1 me enviou mensagens h\u00e1 pouco tempo. Para que eu possa organizar melhor seu atendimento, pe\u00e7o que aguarde alguns minutos antes de enviar novas solicita\u00e7\u00f5es. Obrigada pela compreens\u00e3o! \ud83d\ude4f' : '**\u00cdsis**\\n\\nOi! Vi que voc\u00ea j\u00e1 entrou em contato recentemente. Para que eu possa te ajudar da melhor forma, pe\u00e7o que aguarde um pouquinho antes de enviar novas mensagens. Estou \u00e0 disposi\u00e7\u00e3o! \ud83d\udc99' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "mensagem-cliente-bloqueado",
      "name": "Set - Mensagem Cliente Bloqueado",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        1780,
        420
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(*) as total_mensagens FROM historico_conversas WHERE telefone = $1 AND created_at > NOW() - INTERVAL '1 minute'",
        "options": {
          "queryReplacement": "={{ $json.telefone }}"
        }
      },
      "id": "verificar-rate-limit",
      "name": "DB - Verificar Rate Limit",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        1780,
        180
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "rate-limit-excedido",
              "leftValue": "={{ $json.total_mensagens }}",
              "rightValue": "5",
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "switch-rate-limit",
      "name": "Switch - Rate Limit Excedido?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2000,
        180
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "mensagem_rate_limit",
              "name": "mensagem_final",
              "value": "={{ $('Code - Unificar Dados Cliente').item.json.assistente_atual === 'luana' ? '**Luana**\\n\\nOi! Percebi que voc\u00ea est\u00e1 enviando muitas mensagens seguidas. Calma, estou aqui! \ud83d\ude0a Vou precisar de alguns minutos para processar tudo com aten\u00e7\u00e3o. Me d\u00e1 um tempinho? Prometo que logo volto com tudo organizado! \ud83c\udf19' : $('Code - Unificar Dados Cliente').item.json.assistente_atual === 'camila' ? '**Camila**\\n\\nOl\u00e1! Notei v\u00e1rias mensagens suas em sequ\u00eancia. Para garantir que eu processe tudo corretamente, vou precisar de alguns minutos. Aguarde um pouquinho, por favor! \ud83d\ude4f' : '**\u00cdsis**\\n\\nOi! Vi que voc\u00ea est\u00e1 enviando v\u00e1rias mensagens. Para que eu possa te ajudar melhor, vou precisar de alguns minutos para organizar tudo. Aguarde s\u00f3 um pouquinho! \ud83d\udc99' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "mensagem-rate-limit",
      "name": "Set - Mensagem Rate Limit",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        2220,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "tipo-audio",
              "leftValue": "={{ $('Extrair - Dados do Webhook').item.json.tipo_mensagem }}",
              "rightValue": "audio",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "tipo-imagem",
              "leftValue": "={{ $('Extrair - Dados do Webhook').item.json.tipo_mensagem }}",
              "rightValue": "imagem",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "switch-tipo-mensagem",
      "name": "Switch - Tipo de Mensagem",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        2220,
        180
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO historico_conversas (telefone, mensagem, tipo_mensagem, assistente, fase, sentimento) VALUES ($1, $2, $3, $4, $5, 'neutro') RETURNING *",
        "options": {}
      },
      "id": "salvar-historico",
      "name": "DB - Salvar no Hist\u00f3rico",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        2440,
        60
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "param1",
              "name": "param1",
              "value": "={{ $('Code - Unificar Dados Cliente').item.json.telefone }}",
              "type": "string"
            },
            {
              "id": "param2",
              "name": "param2",
              "value": "={{ $('Extrair - Dados do Webhook').item.json.mensagem_texto }}",
              "type": "string"
            },
            {
              "id": "param3",
              "name": "param3",
              "value": "={{ $('Extrair - Dados do Webhook').item.json.tipo_mensagem }}",
              "type": "string"
            },
            {
              "id": "param4",
              "name": "param4",
              "value": "={{ $('Code - Unificar Dados Cliente').item.json.assistente_atual }}",
              "type": "string"
            },
            {
              "id": "param5",
              "name": "param5",
              "value": "={{ $('Code - Unificar Dados Cliente').item.json.fase_atual }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "preparar-params-historico",
      "name": "Set - Preparar Params Hist\u00f3rico",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        2440,
        180
      ]
    },
    {
      "parameters": {
        "url": "={{ $env.EVOLUTION_API_URL }}/message/sendText/{{ $env.EVOLUTION_INSTANCE }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"number\": \"{{ $('Code - Unificar Dados Cliente').item.json.telefone }}\",\n  \"text\": \"{{ $json.mensagem_final }}\"\n}",
        "options": {}
      },
      "id": "enviar-whatsapp-bloqueio",
      "name": "WhatsApp - Enviar Bloqueio/Rate Limit",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2660,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={ \"success\": true, \"message\": \"Mensagem processada\" }",
        "options": {}
      },
      "id": "webhook-response-ok",
      "name": "Webhook Response - OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        2880,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "checkpoint",
              "name": "checkpoint",
              "value": "bloco_01_completo",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "checkpoint-bloco-01",
      "name": "Checkpoint - Bloco 01",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        3100,
        300
      ]
    },
    {
      "parameters": {
        "url": "={{ $env.EVOLUTION_API_URL }}/message/{{ $('Extrair - Dados do Webhook').item.json.messageId }}/base64",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "obter-audio-base64",
      "name": "Evolution - Obter \u00c1udio Base64",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2440,
        400
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const base64Audio = $json.base64;\nconst audioBuffer = Buffer.from(base64Audio, 'base64');\n\nreturn {\n  binary: {\n    data: audioBuffer\n  },\n  json: {\n    mimeType: 'audio/ogg',\n    fileName: 'audio.ogg'\n  }\n};"
      },
      "id": "converter-audio-buffer",
      "name": "Code - Converter \u00c1udio para Buffer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2660,
        400
      ]
    },
    {
      "parameters": {
        "resource": "audio",
        "operation": "transcribe",
        "options": {
          "language": "pt",
          "temperature": 0
        }
      },
      "id": "openai-whisper-transcrever",
      "name": "OpenAI - Transcrever \u00c1udio (Whisper)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.3,
      "position": [
        2880,
        400
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "mensagem_texto",
              "name": "mensagem_texto_transcrita",
              "value": "={{ $json.text }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "set-texto-transcrito",
      "name": "Set - Texto Transcrito",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        3100,
        400
      ]
    },
    {
      "parameters": {
        "url": "={{ $env.EVOLUTION_API_URL }}/message/{{ $('Extrair - Dados do Webhook').item.json.messageId }}/base64",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "obter-imagem-base64",
      "name": "Evolution - Obter Imagem Base64",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2440,
        520
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {
          "temperature": 0.3,
          "maxTokens": 500
        },
        "messages": {
          "values": [
            {
              "role": "user",
              "content": [
                {
                  "type": "text",
                  "text": "Analise esta imagem enviada pelo cliente e descreva o que voc\u00ea v\u00ea. Se for relacionado a viagens, destinos, documentos ou d\u00favidas sobre pacotes, descreva detalhadamente."
                },
                {
                  "type": "imageUrl",
                  "imageUrl": "={{ 'data:image/jpeg;base64,' + $json.base64 }}"
                }
              ]
            }
          ]
        }
      },
      "id": "openai-vision-analisar",
      "name": "OpenAI - Analisar Imagem (Vision)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.3,
      "position": [
        2660,
        520
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "descricao_imagem",
              "name": "descricao_imagem",
              "value": "={{ $json.choices[0].message.content }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "set-descricao-imagem",
      "name": "Set - Descri\u00e7\u00e3o da Imagem",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        2880,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "const tipoMensagem = $('Extrair - Dados do Webhook').item.json.tipo_mensagem;\nconst cliente = $('Code - Unificar Dados Cliente').item.json;\n\nlet mensagemFinal = '';\nlet tipoFinal = 'texto';\n\nif (tipoMensagem === 'audio') {\n  mensagemFinal = $('Set - Texto Transcrito').item.json.mensagem_texto_transcrita;\n  tipoFinal = 'audio_transcrito';\n} else if (tipoMensagem === 'imagem') {\n  mensagemFinal = `[Imagem enviada] ${$('Set - Descri\u00e7\u00e3o da Imagem').item.json.descricao_imagem}`;\n  tipoFinal = 'imagem_analisada';\n} else {\n  mensagemFinal = $('Extrair - Dados do Webhook').item.json.mensagem_texto;\n  tipoFinal = 'texto';\n}\n\nreturn {\n  json: {\n    ...cliente,\n    mensagem_processada: mensagemFinal,\n    tipo_mensagem_processada: tipoFinal,\n    mensagem_original: $('Extrair - Dados do Webhook').item.json.mensagem_texto\n  }\n};"
      },
      "id": "merge-mensagens-processadas",
      "name": "Code - Merge Mensagens Processadas",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3100,
        520
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT * FROM reservas WHERE telefone = $1 AND status_reserva IN ('aguardando_dados', 'aguardando_pagamento', 'pix_gerado') ORDER BY created_at DESC LIMIT 1",
        "options": {
          "queryReplacement": "={{ $json.telefone }}"
        }
      },
      "id": "buscar-reserva-ativa",
      "name": "DB - Buscar Reserva Ativa",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        3320,
        520
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const cliente = $input.item.json;\nconst reserva = $input.item.json.reserva || null;\n\nlet assistenteDetectado = cliente.assistente_atual || 'luana';\nlet faseDetectada = cliente.fase_atual || 'inicial';\n\nif (reserva && reserva.id) {\n  if (reserva.status_reserva === 'aguardando_dados') {\n    assistenteDetectado = 'camila';\n    faseDetectada = 'coleta_dados';\n  } else if (reserva.status_reserva === 'aguardando_pagamento' || reserva.status_reserva === 'pix_gerado') {\n    assistenteDetectado = 'camila';\n    faseDetectada = 'pagamento';\n  } else if (reserva.status_reserva === 'confirmada') {\n    assistenteDetectado = 'isis';\n    faseDetectada = 'pos_venda';\n  }\n} else {\n  assistenteDetectado = 'luana';\n  faseDetectada = cliente.fase_atual || 'inicial';\n}\n\nreturn {\n  json: {\n    ...cliente,\n    assistente_detectado: assistenteDetectado,\n    fase_detectada: faseDetectada,\n    reserva_ativa: reserva\n  }\n};"
      },
      "id": "detectar-assistente",
      "name": "Code - Detectar Assistente",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3540,
        520
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE clientes SET assistente_atual = $1, fase_atual = $2, updated_at = NOW() WHERE telefone = $3 RETURNING *",
        "options": {}
      },
      "id": "atualizar-assistente-cliente",
      "name": "DB - Atualizar Assistente do Cliente",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        3760,
        520
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "param1",
              "name": "param1",
              "value": "={{ $('Code - Detectar Assistente').item.json.assistente_detectado }}",
              "type": "string"
            },
            {
              "id": "param2",
              "name": "param2",
              "value": "={{ $('Code - Detectar Assistente').item.json.fase_detectada }}",
              "type": "string"
            },
            {
              "id": "param3",
              "name": "param3",
              "value": "={{ $('Code - Detectar Assistente').item.json.telefone }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "preparar-params-update-assistente",
      "name": "Set - Params Update Assistente",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        3760,
        400
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT mensagem, assistente, created_at FROM historico_conversas WHERE telefone = $1 ORDER BY created_at DESC LIMIT 10",
        "options": {
          "queryReplacement": "={{ $json.telefone }}"
        }
      },
      "id": "buscar-historico-conversa",
      "name": "DB - Buscar Hist\u00f3rico de Conversa",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        3980,
        520
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT * FROM pacotes WHERE ativo = true ORDER BY ordem",
        "options": {}
      },
      "id": "buscar-pacotes-disponiveis",
      "name": "DB - Buscar Pacotes Dispon\u00edveis",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        4200,
        520
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "checkpoint",
              "name": "checkpoint",
              "value": "bloco_02_completo",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "checkpoint-bloco-02",
      "name": "Checkpoint - Bloco 02",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        4420,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "const cliente = $('DB - Atualizar Assistente do Cliente').item.json;\nconst mensagemProcessada = $('Code - Merge Mensagens Processadas').item.json.mensagem_processada;\nconst historico = $('DB - Buscar Hist\u00f3rico de Conversa').all().map(h => h.json);\nconst pacotes = $('DB - Buscar Pacotes Dispon\u00edveis').all().map(p => p.json);\nconst reserva = $('Code - Detectar Assistente').item.json.reserva_ativa;\n\nconst historicoFormatado = historico.reverse().map(h => \n  `${h.assistente}: ${h.mensagem}`\n).join('\\n');\n\nconst pacotesFormatados = pacotes.map(p => \n  `- ${p.nome}: ${p.descricao_curta} | Valor: R$ ${p.valor_base} | Dura\u00e7\u00e3o: ${p.duracao}`\n).join('\\n');\n\nconst dadosCliente = `\nNome: ${cliente.nome || 'N\u00e3o informado'}\nTelefone: ${cliente.telefone}\nFase Atual: ${cliente.fase_atual}\n\u00daltimo Pacote Consultado: ${cliente.ultimo_pacote_consultado || 'Nenhum'}\n`;\n\nconst dadosReserva = reserva ? `\nReserva Ativa:\n- Pacote: ${reserva.pacote_nome}\n- Status: ${reserva.status_reserva}\n- Valor Total: R$ ${reserva.valor_total}\n- Pessoas: ${reserva.numero_pessoas}\n- Data In\u00edcio: ${reserva.data_inicio || 'N\u00e3o definida'}\n` : '';\n\nreturn {\n  json: {\n    cliente: cliente,\n    mensagem_cliente: mensagemProcessada,\n    assistente_atual: cliente.assistente_atual,\n    fase_atual: cliente.fase_atual,\n    contexto: {\n      dados_cliente: dadosCliente,\n      historico_conversa: historicoFormatado,\n      pacotes_disponiveis: pacotesFormatados,\n      reserva_ativa: dadosReserva\n    }\n  }\n};"
      },
      "id": "construir-contexto-llm",
      "name": "Code - Construir Contexto para LLM",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4640,
        520
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "assistente-luana",
              "leftValue": "={{ $json.assistente_atual }}",
              "rightValue": "luana",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "assistente-camila",
              "leftValue": "={{ $json.assistente_atual }}",
              "rightValue": "camila",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "assistente-isis",
              "leftValue": "={{ $json.assistente_atual }}",
              "rightValue": "isis",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "switch-rotear-assistente",
      "name": "Switch - Rotear para Assistente",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        4860,
        520
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "prompt_luana",
              "name": "prompt_sistema",
              "value": "Voc\u00ea \u00e9 a Luana, consultora de viagens da Lua Nova Trips. Voc\u00ea \u00e9 uma pessoa real, entusiasta de viagens transformadoras, com energia contagiante e paix\u00e3o genu\u00edna por conectar pessoas a experi\u00eancias \u00fanicas. Nunca se apresente como IA ou assistente.\n\n## PERSONALIDADE\n- Comunicativa, emp\u00e1tica e inspiradora\n- Usa linguagem calorosa e acolhedora\n- Faz perguntas abertas para entender sonhos de viagem\n- Compartilha hist\u00f3rias e detalhes que criam conex\u00e3o emocional\n\n## REGRAS DE COMUNICA\u00c7\u00c3O\n- SEMPRE inicie suas mensagens com **Luana** em negrito, seguido de duas quebras de linha\n- Use emojis estrategicamente: m\u00e1ximo 2-3 por mensagem, APENAS no final de frases/blocos, NUNCA no meio de uma frase\n- Seja natural e humana, evite parecer rob\u00f3tica\n- Adapte o tom ao cliente (formal/informal conforme o contexto)\n\n## SUA MISS\u00c3O\n1. Descobrir o que o cliente busca em uma viagem\n2. Apresentar pacotes alinhados aos desejos dele\n3. Criar conex\u00e3o emocional com os destinos\n4. Conduzir naturalmente para o interesse em reservar\n5. Quando o cliente demonstrar interesse concreto, transferir para Camila\n\n## PACOTES DISPON\u00cdVEIS\n{{ $json.contexto.pacotes_disponiveis }}\n\n## DADOS DO CLIENTE\n{{ $json.contexto.dados_cliente }}\n\n## HIST\u00d3RICO DA CONVERSA\n{{ $json.contexto.historico_conversa }}\n\n## MENSAGEM DO CLIENTE\n{{ $json.mensagem_cliente }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "preparar-prompt-luana",
      "name": "Set - Preparar Prompt Luana",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        5080,
        400
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "prompt_camila",
              "name": "prompt_sistema",
              "value": "Voc\u00ea \u00e9 a Camila, especialista em reservas e pagamentos da Lua Nova Trips. Voc\u00ea \u00e9 uma pessoa real, organizada, eficiente e atenciosa. Nunca se apresente como IA ou assistente.\n\n## PERSONALIDADE\n- Profissional, clara e objetiva\n- Paciente e did\u00e1tica ao explicar processos\n- Atenta aos detalhes e prazos\n- Transmite seguran\u00e7a e confian\u00e7a\n\n## REGRAS DE COMUNICA\u00c7\u00c3O\n- SEMPRE inicie suas mensagens com **Camila** em negrito, seguido de duas quebras de linha\n- Use emojis estrategicamente: m\u00e1ximo 2-3 por mensagem, APENAS no final de frases/blocos, NUNCA no meio de uma frase\n- Seja natural e humana, evite parecer rob\u00f3tica\n\n## SUA MISS\u00c3O\n1. Coletar dados necess\u00e1rios para reserva (nome completo, CPF, email)\n2. Confirmar detalhes da viagem (datas, n\u00famero de pessoas, acomoda\u00e7\u00e3o)\n3. Processar pagamento (PIX ou cart\u00e3o via gerente)\n4. Acompanhar confirma\u00e7\u00e3o de pagamento\n5. Ap\u00f3s confirma\u00e7\u00e3o, transferir para \u00cdsis\n\n## DADOS DO CLIENTE\n{{ $json.contexto.dados_cliente }}\n\n## RESERVA ATIVA\n{{ $json.contexto.reserva_ativa }}\n\n## HIST\u00d3RICO DA CONVERSA\n{{ $json.contexto.historico_conversa }}\n\n## MENSAGEM DO CLIENTE\n{{ $json.mensagem_cliente }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "preparar-prompt-camila",
      "name": "Set - Preparar Prompt Camila",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        5080,
        520
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "prompt_isis",
              "name": "prompt_sistema",
              "value": "Voc\u00ea \u00e9 a \u00cdsis, especialista em p\u00f3s-venda e suporte da Lua Nova Trips. Voc\u00ea \u00e9 uma pessoa real, prestativa, emp\u00e1tica e sempre disposta a ajudar. Nunca se apresente como IA ou assistente.\n\n## PERSONALIDADE\n- Acolhedora e atenciosa\n- Proativa em antecipar necessidades\n- Resolve problemas com calma e efici\u00eancia\n- Mant\u00e9m o cliente informado e tranquilo\n\n## REGRAS DE COMUNICA\u00c7\u00c3O\n- SEMPRE inicie suas mensagens com **\u00cdsis** em negrito, seguido de duas quebras de linha\n- Use emojis estrategicamente: m\u00e1ximo 2-3 por mensagem, APENAS no final de frases/blocos, NUNCA no meio de uma frase\n- Seja natural e humana, evite parecer rob\u00f3tica\n\n## SUA MISS\u00c3O\n1. Fornecer informa\u00e7\u00f5es sobre a viagem confirmada\n2. Responder d\u00favidas sobre documenta\u00e7\u00e3o, roteiro, etc\n3. Oferecer suporte durante a viagem (se necess\u00e1rio)\n4. Coletar feedback ap\u00f3s a viagem\n5. Identificar oportunidades de novas viagens\n\n## DADOS DO CLIENTE\n{{ $json.contexto.dados_cliente }}\n\n## RESERVA CONFIRMADA\n{{ $json.contexto.reserva_ativa }}\n\n## HIST\u00d3RICO DA CONVERSA\n{{ $json.contexto.historico_conversa }}\n\n## MENSAGEM DO CLIENTE\n{{ $json.mensagem_cliente }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "preparar-prompt-isis",
      "name": "Set - Preparar Prompt \u00cdsis",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        5080,
        640
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "checkpoint",
              "name": "checkpoint",
              "value": "bloco_03_completo",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "checkpoint-bloco-03",
      "name": "Checkpoint - Bloco 03",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        5300,
        520
      ]
    },
    {
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {
          "temperature": 0.7,
          "maxTokens": 800
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "={{ $json.prompt_sistema }}"
            },
            {
              "role": "user",
              "content": "={{ $('Code - Construir Contexto para LLM').item.json.mensagem_cliente }}"
            }
          ]
        }
      },
      "id": "openai-luana",
      "name": "OpenAI - Luana (Chat)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.3,
      "position": [
        5300,
        400
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {
          "temperature": 0.5,
          "maxTokens": 800
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "={{ $json.prompt_sistema }}"
            },
            {
              "role": "user",
              "content": "={{ $('Code - Construir Contexto para LLM').item.json.mensagem_cliente }}"
            }
          ]
        }
      },
      "id": "openai-camila",
      "name": "OpenAI - Camila (Chat)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.3,
      "position": [
        5300,
        520
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {
          "temperature": 0.6,
          "maxTokens": 800
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "={{ $json.prompt_sistema }}"
            },
            {
              "role": "user",
              "content": "={{ $('Code - Construir Contexto para LLM').item.json.mensagem_cliente }}"
            }
          ]
        }
      },
      "id": "openai-isis",
      "name": "OpenAI - \u00cdsis (Chat)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.3,
      "position": [
        5300,
        640
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const resposta = $json.choices?.[0]?.message?.content || $json.message?.content || $json.text || '';\n\nreturn {\n  json: {\n    resposta_llm: resposta,\n    assistente: $('Code - Construir Contexto para LLM').item.json.assistente_atual,\n    cliente: $('Code - Construir Contexto para LLM').item.json.cliente\n  }\n};"
      },
      "id": "extrair-resposta-llm",
      "name": "Code - Extrair Resposta LLM",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        5520,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "const mensagem = $json.resposta_llm;\nconst emojiRegex = /([\\p{Emoji}\\u200d]+)/gu;\nconst linhas = mensagem.split('\\n');\n\nlet mensagemCorrigida = '';\nlet totalEmojis = 0;\n\nfor (let linha of linhas) {\n  if (linha.includes('CPF:') || linha.includes('Email:') || linha.includes('Telefone:')) {\n    mensagemCorrigida += linha + '\\n';\n    continue;\n  }\n\n  const emojisNaLinha = linha.match(emojiRegex) || [];\n  totalEmojis += emojisNaLinha.length;\n\n  let linhaLimpa = linha;\n  const palavras = linha.split(' ');\n  \n  for (let i = 0; i < palavras.length - 1; i++) {\n    if (emojiRegex.test(palavras[i])) {\n      palavras[i] = palavras[i].replace(emojiRegex, '');\n    }\n  }\n\n  linhaLimpa = palavras.join(' ');\n  mensagemCorrigida += linhaLimpa + '\\n';\n}\n\nif (totalEmojis > 3) {\n  let count = 0;\n  mensagemCorrigida = mensagemCorrigida.replace(emojiRegex, (match) => {\n    count++;\n    return count <= 3 ? match : '';\n  });\n}\n\nreturn {\n  json: {\n    ...$json,\n    resposta_validada: mensagemCorrigida.trim()\n  }\n};"
      },
      "id": "validar-emojis",
      "name": "Code - Validar Posi\u00e7\u00e3o de Emojis",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        5740,
        520
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "checkpoint",
              "name": "checkpoint",
              "value": "bloco_04_completo",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "checkpoint-bloco-04",
      "name": "Checkpoint - Bloco 04",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        5960,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "// Detectar inten\u00e7\u00f5es na resposta do LLM\nconst resposta = $json.resposta_validada.toLowerCase();\nconst cliente = $json.cliente;\n\nlet intencoes = {\n  enviar_imagem_pacote: false,\n  criar_reserva: false,\n  coletar_dados: false,\n  gerar_pix: false,\n  pacote_mencionado: null\n};\n\n// Detectar men\u00e7\u00e3o a pacotes espec\u00edficos\nconst pacotes = ['len\u00e7\u00f3is', 'lencois', 'chapada', 'jalap\u00e3o', 'jalapao', 'bonito'];\nfor (const pacote of pacotes) {\n  if (resposta.includes(pacote)) {\n    intencoes.pacote_mencionado = pacote;\n    break;\n  }\n}\n\n// Detectar inten\u00e7\u00e3o de enviar imagem\nif (resposta.includes('vou te enviar') && (resposta.includes('foto') || resposta.includes('imagem'))) {\n  intencoes.enviar_imagem_pacote = true;\n}\n\n// Detectar inten\u00e7\u00e3o de criar reserva\nif (resposta.includes('vamos iniciar') || resposta.includes('fazer a reserva') || resposta.includes('confirmar sua reserva')) {\n  intencoes.criar_reserva = true;\n}\n\n// Detectar coleta de dados\nif (resposta.includes('nome completo') || resposta.includes('cpf') || resposta.includes('e-mail')) {\n  intencoes.coletar_dados = true;\n}\n\n// Detectar gera\u00e7\u00e3o de PIX\nif (resposta.includes('pix') && (resposta.includes('gerar') || resposta.includes('enviar'))) {\n  intencoes.gerar_pix = true;\n}\n\nreturn {\n  json: {\n    ...$json,\n    intencoes: intencoes\n  }\n};"
      },
      "id": "detectar-intencoes",
      "name": "Code - Detectar Inten\u00e7\u00f5es",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        6180,
        520
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "deve-enviar-imagem",
              "leftValue": "={{ $json.intencoes.enviar_imagem_pacote }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "switch-enviar-imagem",
      "name": "Switch - Deve Enviar Imagem?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        6400,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "// Buscar URL da imagem do pacote no Google Drive\nconst pacoteMencionado = $json.intencoes.pacote_mencionado;\n\nif (!pacoteMencionado) {\n  return {\n    json: {\n      ...$json,\n      imagem_url: null,\n      erro: 'Nenhum pacote mencionado'\n    }\n  };\n}\n\n// Mapeamento de pacotes para URLs do Google Drive (p\u00fablico)\nconst imagensPacotes = {\n  'len\u00e7\u00f3is': process.env.GDRIVE_LENCOIS_URL,\n  'lencois': process.env.GDRIVE_LENCOIS_URL,\n  'chapada': process.env.GDRIVE_CHAPADA_URL,\n  'jalap\u00e3o': process.env.GDRIVE_JALAPAO_URL,\n  'jalapao': process.env.GDRIVE_JALAPAO_URL,\n  'bonito': process.env.GDRIVE_BONITO_URL\n};\n\nconst imagemUrl = imagensPacotes[pacoteMencionado] || null;\n\nreturn {\n  json: {\n    ...$json,\n    imagem_url: imagemUrl\n  }\n};"
      },
      "id": "buscar-imagem-pacote",
      "name": "Code - Buscar URL Imagem Pacote",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        6620,
        400
      ]
    },
    {
      "parameters": {
        "url": "={{ $env.EVOLUTION_API_URL }}/message/sendMedia/{{ $env.EVOLUTION_INSTANCE }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"number\": \"{{ $json.cliente.telefone }}\",\n  \"mediaUrl\": \"{{ $json.imagem_url }}\",\n  \"mediaType\": \"image\"\n}",
        "options": {}
      },
      "id": "whatsapp-enviar-imagem",
      "name": "WhatsApp - Enviar Imagem Pacote",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        6840,
        400
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "amount": 2,
        "unit": "seconds"
      },
      "id": "wait-apos-imagem",
      "name": "Wait - Ap\u00f3s Imagem",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        7060,
        400
      ]
    },
    {
      "parameters": {
        "url": "={{ $env.EVOLUTION_API_URL }}/message/sendText/{{ $env.EVOLUTION_INSTANCE }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"number\": \"{{ $('Code - Detectar Inten\u00e7\u00f5es').item.json.cliente.telefone }}\",\n  \"text\": \"{{ $('Code - Detectar Inten\u00e7\u00f5es').item.json.resposta_validada }}\"\n}",
        "options": {}
      },
      "id": "whatsapp-enviar-texto",
      "name": "WhatsApp - Enviar Mensagem Texto",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        7280,
        520
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO historico_conversas (telefone, mensagem, tipo_mensagem, assistente, fase, sentimento) VALUES ($1, $2, 'resposta', $3, $4, 'neutro') RETURNING *",
        "options": {}
      },
      "id": "salvar-resposta-historico",
      "name": "DB - Salvar Resposta no Hist\u00f3rico",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        7500,
        520
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "param1",
              "name": "param1",
              "value": "={{ $('Code - Detectar Inten\u00e7\u00f5es').item.json.cliente.telefone }}",
              "type": "string"
            },
            {
              "id": "param2",
              "name": "param2",
              "value": "={{ $('Code - Detectar Inten\u00e7\u00f5es').item.json.resposta_validada }}",
              "type": "string"
            },
            {
              "id": "param3",
              "name": "param3",
              "value": "={{ $('Code - Detectar Inten\u00e7\u00f5es').item.json.assistente }}",
              "type": "string"
            },
            {
              "id": "param4",
              "name": "param4",
              "value": "={{ $('Code - Detectar Inten\u00e7\u00f5es').item.json.cliente.fase_atual }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "preparar-params-salvar-resposta",
      "name": "Set - Params Salvar Resposta",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        7500,
        400
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={ \"success\": true, \"message\": \"Workflow executado com sucesso\", \"assistente\": \"{{ $('Code - Detectar Inten\u00e7\u00f5es').item.json.assistente }}\" }",
        "options": {}
      },
      "id": "webhook-response-final",
      "name": "Webhook Response - Final",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        7720,
        520
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "checkpoint",
              "name": "checkpoint",
              "value": "workflow_completo",
              "type": "string"
            },
            {
              "id": "status",
              "name": "status",
              "value": "sucesso",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "checkpoint-final",
      "name": "\u2705 Checkpoint - WORKFLOW COMPLETO",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.3,
      "position": [
        7940,
        520
      ]
    }
  ],
  "connections": {
    "Webhook - Receber Mensagem": {
      "main": [
        [
          {
            "node": "Extrair - Dados do Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrair - Dados do Webhook": {
      "main": [
        [
          {
            "node": "DB - Buscar Cliente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Buscar Cliente": {
      "main": [
        [
          {
            "node": "Switch - Cliente Existe?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Cliente Existe?": {
      "main": [
        [
          {
            "node": "DB - Atualizar \u00daltima Intera\u00e7\u00e3o",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "DB - Criar Novo Cliente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Criar Novo Cliente": {
      "main": [
        [
          {
            "node": "Code - Unificar Dados Cliente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Atualizar \u00daltima Intera\u00e7\u00e3o": {
      "main": [
        [
          {
            "node": "Code - Unificar Dados Cliente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Unificar Dados Cliente": {
      "main": [
        [
          {
            "node": "Switch - Cliente Bloqueado?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Cliente Bloqueado?": {
      "main": [
        [
          {
            "node": "Set - Mensagem Cliente Bloqueado",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "DB - Verificar Rate Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Mensagem Cliente Bloqueado": {
      "main": [
        [
          {
            "node": "WhatsApp - Enviar Bloqueio/Rate Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Verificar Rate Limit": {
      "main": [
        [
          {
            "node": "Switch - Rate Limit Excedido?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Rate Limit Excedido?": {
      "main": [
        [
          {
            "node": "Set - Mensagem Rate Limit",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Switch - Tipo de Mensagem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Mensagem Rate Limit": {
      "main": [
        [
          {
            "node": "WhatsApp - Enviar Bloqueio/Rate Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Tipo de Mensagem": {
      "main": [
        [
          {
            "node": "Evolution - Obter \u00c1udio Base64",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Evolution - Obter Imagem Base64",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code - Merge Mensagens Processadas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evolution - Obter \u00c1udio Base64": {
      "main": [
        [
          {
            "node": "Code - Converter \u00c1udio para Buffer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Converter \u00c1udio para Buffer": {
      "main": [
        [
          {
            "node": "OpenAI - Transcrever \u00c1udio (Whisper)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Transcrever \u00c1udio (Whisper)": {
      "main": [
        [
          {
            "node": "Set - Texto Transcrito",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Texto Transcrito": {
      "main": [
        [
          {
            "node": "Code - Merge Mensagens Processadas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evolution - Obter Imagem Base64": {
      "main": [
        [
          {
            "node": "OpenAI - Analisar Imagem (Vision)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Analisar Imagem (Vision)": {
      "main": [
        [
          {
            "node": "Set - Descri\u00e7\u00e3o da Imagem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Descri\u00e7\u00e3o da Imagem": {
      "main": [
        [
          {
            "node": "Code - Merge Mensagens Processadas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Merge Mensagens Processadas": {
      "main": [
        [
          {
            "node": "DB - Buscar Reserva Ativa",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Buscar Reserva Ativa": {
      "main": [
        [
          {
            "node": "Code - Detectar Assistente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Detectar Assistente": {
      "main": [
        [
          {
            "node": "Set - Params Update Assistente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Params Update Assistente": {
      "main": [
        [
          {
            "node": "DB - Atualizar Assistente do Cliente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Atualizar Assistente do Cliente": {
      "main": [
        [
          {
            "node": "DB - Buscar Hist\u00f3rico de Conversa",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Buscar Hist\u00f3rico de Conversa": {
      "main": [
        [
          {
            "node": "DB - Buscar Pacotes Dispon\u00edveis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Buscar Pacotes Dispon\u00edveis": {
      "main": [
        [
          {
            "node": "Checkpoint - Bloco 02",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Checkpoint - Bloco 02": {
      "main": [
        [
          {
            "node": "Code - Construir Contexto para LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Construir Contexto para LLM": {
      "main": [
        [
          {
            "node": "Switch - Rotear para Assistente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Rotear para Assistente": {
      "main": [
        [
          {
            "node": "Set - Preparar Prompt Luana",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set - Preparar Prompt Camila",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set - Preparar Prompt \u00cdsis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Preparar Prompt Luana": {
      "main": [
        [
          {
            "node": "OpenAI - Luana (Chat)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Preparar Prompt Camila": {
      "main": [
        [
          {
            "node": "OpenAI - Camila (Chat)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Preparar Prompt \u00cdsis": {
      "main": [
        [
          {
            "node": "OpenAI - \u00cdsis (Chat)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Luana (Chat)": {
      "main": [
        [
          {
            "node": "Code - Extrair Resposta LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Camila (Chat)": {
      "main": [
        [
          {
            "node": "Code - Extrair Resposta LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - \u00cdsis (Chat)": {
      "main": [
        [
          {
            "node": "Code - Extrair Resposta LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Extrair Resposta LLM": {
      "main": [
        [
          {
            "node": "Code - Validar Posi\u00e7\u00e3o de Emojis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Validar Posi\u00e7\u00e3o de Emojis": {
      "main": [
        [
          {
            "node": "Checkpoint - Bloco 04",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Checkpoint - Bloco 04": {
      "main": [
        [
          {
            "node": "Code - Detectar Inten\u00e7\u00f5es",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Detectar Inten\u00e7\u00f5es": {
      "main": [
        [
          {
            "node": "Switch - Deve Enviar Imagem?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Deve Enviar Imagem?": {
      "main": [
        [
          {
            "node": "Code - Buscar URL Imagem Pacote",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "WhatsApp - Enviar Mensagem Texto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Buscar URL Imagem Pacote": {
      "main": [
        [
          {
            "node": "WhatsApp - Enviar Imagem Pacote",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WhatsApp - Enviar Imagem Pacote": {
      "main": [
        [
          {
            "node": "Wait - Ap\u00f3s Imagem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait - Ap\u00f3s Imagem": {
      "main": [
        [
          {
            "node": "WhatsApp - Enviar Mensagem Texto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WhatsApp - Enviar Mensagem Texto": {
      "main": [
        [
          {
            "node": "Set - Params Salvar Resposta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Params Salvar Resposta": {
      "main": [
        [
          {
            "node": "DB - Salvar Resposta no Hist\u00f3rico",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Salvar Resposta no Hist\u00f3rico": {
      "main": [
        [
          {
            "node": "Webhook Response - Final",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Response - Final": {
      "main": [
        [
          {
            "node": "\u2705 Checkpoint - WORKFLOW COMPLETO",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set - Preparar Params Hist\u00f3rico": {
      "main": [
        [
          {
            "node": "DB - Salvar no Hist\u00f3rico",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Salvar no Hist

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Lua Nova - Sistema Completo. Uses postgres, httpRequest, openAi. Webhook trigger; 55 nodes.

Source: https://gist.github.com/gustavoxdsgn-glitch/daac9eb932aaa55a608025255e9cf11d — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Eu Clara – Funil Kiwify Completo. Uses postgres, openAi, httpRequest, gmail. Webhook trigger; 70 nodes.

Postgres, OpenAI, HTTP Request +1
AI & RAG

User Signup & Verification: The workflow starts when a user signs up. It generates a verification code and sends it via SMS using Twilio. Code Validation: The user replies with the code. The workflow

Postgres, HTTP Request, OpenAI +2
AI & RAG

Send-Outreach. Uses postgres, openAi, httpRequest, emailSend. Webhook trigger; 15 nodes.

Postgres, OpenAI, HTTP Request +1
AI & RAG

AI Resume Screening Workflow. Uses openAi, emailSend, httpRequest, postgres. Webhook trigger; 14 nodes.

OpenAI, Email Send, HTTP Request +2
AI & RAG

WhatsApp - Receive Messages. Uses postgres, openAi, httpRequest. Webhook trigger; 12 nodes.

Postgres, OpenAI, HTTP Request