AutomationFlowsAI & RAG › Follow-up Automatizado

Follow-up Automatizado

Follow-up Automatizado. Uses supabase, openAi, twilio, httpRequest. Scheduled trigger; 11 nodes.

Cron / scheduled trigger★★★★☆ complexityAI-powered11 nodesSupabaseOpenAITwilioHTTP Request
AI & RAG Trigger: Cron / scheduled Nodes: 11 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": "Follow-up Automatizado",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "minutesInterval": 1,
              "triggerAtHour": 10
            }
          ]
        }
      },
      "name": "Agendador Follow-up",
      "type": "n8n-nodes-base.cron",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "id": "a0800e83-1100-4cff-b137-84781f2c9979"
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "clientes_finais",
        "filters": {
          "conditions": [
            {
              "keyName": "modo",
              "keyValue": "em aberto"
            }
          ]
        }
      },
      "name": "Buscar Clientes Pendentes",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        200,
        0
      ],
      "id": "ce5a0278-eba1-40c4-979a-b152a51e31a9",
      "alwaysOutputData": true,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT me.* FROM mensagens_enviadas me\nJOIN clientes_finais cf ON me.cliente_final_id = cf.id\nWHERE cf.modo = 'em aberto'\nAND me.timestamp = (\n  SELECT MAX(timestamp) FROM mensagens_enviadas\n  WHERE cliente_final_id = cf.id\n)"
      },
      "name": "Buscar Ultima Mensagem",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        400,
        0
      ],
      "id": "ce5a0278-eba1-40c4-979a-b152a51e31b1",
      "alwaysOutputData": true,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Filtrar clientes que precisam de follow-up\n// Ajustar para o fuso hor\u00e1rio brasileiro (GMT-3)\nconst agora = new Date();\n\n// Fun\u00e7\u00e3o para ajustar timestamp para fuso hor\u00e1rio brasileiro\nfunction ajustarParaFusoBrasil(data) {\n  // Criar uma string de data no formato ISO com o fuso hor\u00e1rio de S\u00e3o Paulo\n  const dataString = data.toLocaleString('en-US', { timeZone: 'America/Sao_Paulo' });\n  // Converter de volta para objeto Date\n  return new Date(dataString);\n}\n\n// Ajustar a data atual para o fuso hor\u00e1rio brasileiro\nconst agoraBrasil = ajustarParaFusoBrasil(agora);\nconsole.log('Data atual (fuso BR):', agoraBrasil);\n\nconst clientesParaFollowUp = [];\n\n// Obter todas as \u00faltimas mensagens\nconst ultimasMensagens = $node[\"Buscar Ultima Mensagem\"].json;\n\nfor (const item of $input.all()) {\n  const cliente = item.json;\n  \n  // Encontrar a \u00faltima mensagem deste cliente\n  const ultimaMensagem = ultimasMensagens.find(m => m.cliente_final_id === cliente.id);\n  \n  // Verificar se tem \u00faltima mensagem\n  if (!ultimaMensagem || !ultimaMensagem.timestamp) continue;\n  \n  // Converter para data e ajustar para fuso hor\u00e1rio brasileiro\n  const dataUltimaMensagem = new Date(ultimaMensagem.timestamp);\n  const dataUltimaMensagemBR = ajustarParaFusoBrasil(dataUltimaMensagem);\n  \n  console.log(`Cliente ${cliente.id} - \u00daltima mensagem:`, dataUltimaMensagemBR);\n  \n  // Calcular diferen\u00e7a em dias (usando datas no mesmo fuso)\n  const diffTime = Math.abs(agoraBrasil - dataUltimaMensagemBR);\n  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n  \n  console.log(`Cliente ${cliente.id} - Dias desde \u00faltima mensagem:`, diffDays);\n  \n  // Adicionar tipo de follow-up baseado no tempo\n  if (diffDays === 1) {\n    clientesParaFollowUp.push({\n      ...cliente,\n      tipoFollowUp: 'lembrete_leve',\n      diasEspera: diffDays,\n      ultimaMensagemData: ultimaMensagem.timestamp\n    });\n  } else if (diffDays === 3) {\n    clientesParaFollowUp.push({\n      ...cliente,\n      tipoFollowUp: 'reforcar_beneficio',\n      diasEspera: diffDays,\n      ultimaMensagemData: ultimaMensagem.timestamp\n    });\n  } else if (diffDays === 7) {\n    clientesParaFollowUp.push({\n      ...cliente,\n      tipoFollowUp: 'encerramento',\n      diasEspera: diffDays,\n      ultimaMensagemData: ultimaMensagem.timestamp\n    });\n  }\n}\n\n// Retornar apenas clientes que precisam de follow-up\nreturn clientesParaFollowUp.map(cliente => ({ json: cliente }));"
      },
      "name": "Filtrar Follow-ups",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        0
      ],
      "id": "37b14782-e647-489a-852e-ea6148f70d27"
    },
    {
      "parameters": {
        "options": {}
      },
      "name": "Loop Clientes",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        800,
        0
      ],
      "id": "ed981d1b-4a0a-4075-9672-133a7eaecab3"
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "resource": "chat",
        "prompt": {
          "messages": [
            {
              "role": "system",
              "content": "Voc\u00ea \u00e9 um assistente especializado em follow-up de vendas. Crie mensagens curtas, amig\u00e1veis e naturais para WhatsApp."
            },
            {
              "role": "user",
              "content": "=Crie uma mensagem de follow-up para um cliente chamado {{$json.nome}}. Passaram-se {{$json.diasEspera}} dias desde a \u00faltima intera\u00e7\u00e3o.\n\nTipo de follow-up: {{$json.tipoFollowUp}}\n\nSe o tipo for 'lembrete_leve', envie uma mensagem simp\u00e1tica perguntando se o cliente viu as informa\u00e7\u00f5es enviadas anteriormente.\n\nSe o tipo for 'reforcar_beneficio', reforce os benef\u00edcios do servi\u00e7o e pergunte se o cliente tem alguma d\u00favida espec\u00edfica.\n\nSe o tipo for 'encerramento', informe que o atendimento ser\u00e1 encerrado, mas que o cliente pode entrar em contato quando quiser.\n\nA mensagem deve ser curta (m\u00e1ximo 3 linhas), amig\u00e1vel e natural, como se fosse enviada por uma pessoa real. N\u00e3o mencione que \u00e9 um follow-up automatizado."
            }
          ]
        },
        "options": {
          "model": "gpt-3.5-turbo",
          "temperature": 0.7,
          "maxTokens": 150,
          "additionalProperties": {}
        },
        "simplifyOutput": true
      },
      "name": "Gerar Mensagem Follow-up",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.8,
      "position": [
        1000,
        0
      ],
      "id": "73c21b6d-6374-4eec-8d62-d63121c0757a",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Depurar a sa\u00edda do OpenAI\nconst openAIOutput = $input.first().json;\nconsole.log('Sa\u00edda do OpenAI:', JSON.stringify(openAIOutput, null, 2));\n\n// Tentar extrair a mensagem de diferentes formatos poss\u00edveis\nlet mensagem = '';\nif (typeof openAIOutput === 'string') {\n  mensagem = openAIOutput;\n} else if (openAIOutput.text) {\n  mensagem = openAIOutput.text;\n} else if (openAIOutput.content) {\n  mensagem = openAIOutput.content;\n} else if (openAIOutput.choices && openAIOutput.choices[0]) {\n  mensagem = openAIOutput.choices[0].message?.content || '';\n}\n\nconsole.log('Mensagem extra\u00edda:', mensagem);\n\n// Garantir que temos uma mensagem padr\u00e3o se nada for encontrado\nif (!mensagem) {\n  if ($node[\"Loop Clientes\"].json.tipoFollowUp === 'lembrete_leve') {\n    mensagem = `Ol\u00e1 ${$node[\"Loop Clientes\"].json.nome}! S\u00f3 passando para saber se voc\u00ea chegou a ver as informa\u00e7\u00f5es que te enviei. Estou \u00e0 disposi\u00e7\u00e3o para qualquer d\u00favida! \ud83d\ude0a`;\n  } else if ($node[\"Loop Clientes\"].json.tipoFollowUp === 'reforcar_beneficio') {\n    mensagem = `Oi ${$node[\"Loop Clientes\"].json.nome}! Lembra que conversamos sobre nossos planos? Eles oferecem o melhor custo-benef\u00edcio do mercado. Posso te ajudar com alguma d\u00favida espec\u00edfica?`;\n  } else {\n    mensagem = `Ol\u00e1 ${$node[\"Loop Clientes\"].json.nome}, estou encerrando seu atendimento por aqui, mas fique \u00e0 vontade para me chamar quando precisar! Estamos sempre \u00e0 disposi\u00e7\u00e3o. \ud83d\ude4c`;\n  }\n}\n\nreturn [{\n  json: {\n    mensagemGerada: mensagem\n  }\n}];"
      },
      "name": "Debug OpenAI",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        0
      ],
      "id": "7f42255f-8548-424d-b4c3-438f05afd5a6"
    },
    {
      "parameters": {
        "jsCode": "// Obter o n\u00famero do Twilio para envio\n// Normalmente seria armazenado em uma configura\u00e7\u00e3o ou obtido de algum lugar\n\nreturn [{\n  json: {\n    numeroRemetente: \"+554791950615\", // N\u00famero do Twilio\n    mensagemParaEnviar: $node[\"Debug OpenAI\"].json.mensagemGerada,\n    // Adicionar o objeto de template para Twilio\n    templateMessage: {\n      contentSid: \"HX38750d6132324abf885b19cf849a174a\",\n      contentVariables: JSON.stringify({ 1: $node[\"Loop Clientes\"].json.nome }),\n      from: \"whatsapp:+554791950615\",\n      messagingServiceSid: \"MG5a4f738ce460da454c99e80a5df23996\",\n      to: \"whatsapp:\" + $node[\"Loop Clientes\"].json.whatsapp,\n      // Adicionar o body para evitar o erro\n      body: $node[\"Debug OpenAI\"].json.mensagemGerada\n    }\n  }\n}];"
      },
      "name": "Buscar N\u00famero Twilio",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1200,
        0
      ],
      "id": "7f42255f-8548-424d-b4c3-438f05afd5a5"
    },
    {
      "parameters": {
        "from": "={{$node[\"Buscar N\u00famero Twilio\"].json.numeroRemetente}}",
        "to": "={{$node[\"Loop Clientes\"].json.whatsapp}}",
        "toWhatsapp": true,
        "message": "={{$node[\"Buscar N\u00famero Twilio\"].json.mensagemParaEnviar}}",
        "options": {}
      },
      "name": "Enviar WhatsApp",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1400,
        0
      ],
      "id": "a91534de-6b85-4394-b82b-ebadc0cb4cea",
      "credentials": {
        "twilioApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=http://supabase-server:3001/api/registrar-mensagem",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "whatsappNumero",
              "value": "={{$node[\"Buscar N\u00famero Twilio\"].json.numeroRemetente}}"
            },
            {
              "name": "pergunta",
              "value": "follow-up autom\u00e1tico"
            },
            {
              "name": "resposta",
              "value": "={{$node[\"Buscar N\u00famero Twilio\"].json.mensagemParaEnviar}}"
            },
            {
              "name": "numeroDestino",
              "value": "={{$node[\"Loop Clientes\"].json.whatsapp}}"
            },
            {
              "name": "nome",
              "value": "={{$node[\"Loop Clientes\"].json.nome}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Registrar Mensagem",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        1600,
        0
      ],
      "id": "1a1bf06c-8f9d-4f0a-88bb-d5fb241d3b0c"
    },
    {
      "parameters": {
        "operation": "update",
        "tableId": "clientes_finais",
        "id": "={{$node[\"Loop Clientes\"].json.id}}",
        "updateAllMatching": false,
        "data": {
          "ultimo_followup": "={{$today}}",
          "modo": "={{$node[\"Loop Clientes\"].json.tipoFollowUp === 'encerramento' ? 'encerrado' : 'em aberto'}}",
          "tentativas_followup": "={{$node[\"Loop Clientes\"].json.tentativas_followup ? $node[\"Loop Clientes\"].json.tentativas_followup + 1 : 1}}"
        }
      },
      "name": "Atualizar Status Cliente",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1800,
        0
      ],
      "id": "ce5a0278-eba1-40c4-979a-b152a51e31b0",
      "alwaysOutputData": true,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Agendador Follow-up": {
      "main": [
        [
          {
            "node": "Buscar Clientes Pendentes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar Clientes Pendentes": {
      "main": [
        [
          {
            "node": "Buscar Ultima Mensagem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar Ultima Mensagem": {
      "main": [
        [
          {
            "node": "Filtrar Follow-ups",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filtrar Follow-ups": {
      "main": [
        [
          {
            "node": "Loop Clientes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Clientes": {
      "main": [
        [
          {
            "node": "Gerar Mensagem Follow-up",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gerar Mensagem Follow-up": {
      "main": [
        [
          {
            "node": "Debug OpenAI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Debug OpenAI": {
      "main": [
        [
          {
            "node": "Buscar N\u00famero Twilio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar N\u00famero Twilio": {
      "main": [
        [
          {
            "node": "Enviar WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enviar WhatsApp": {
      "main": [
        [
          {
            "node": "Registrar Mensagem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Registrar Mensagem": {
      "main": [
        [
          {
            "node": "Atualizar Status Cliente",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

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

Follow-up Automatizado. Uses supabase, openAi, twilio, httpRequest. Scheduled trigger; 11 nodes.

Source: https://github.com/1thays4/painel-clientes-ia-ts/blob/main/workflows/n8n-follow-up-workflow-fixed.json — 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

Follow-up Automatizado. Uses supabase, openAi, twilio, httpRequest. Scheduled trigger; 11 nodes.

Supabase, OpenAI, Twilio +1
AI & RAG

Sales Team V2. Uses supabase, httpRequest, crypto, openAi. Scheduled trigger; 25 nodes.

Supabase, HTTP Request, Crypto +2
AI & RAG

This workflow automatically fetches active deals from Zoho CRM, retrieves real-time market signals, calculates AI-enhanced forecast metrics, evaluates deal-market alignment, stores data in a database,

HTTP Request, Zoho Crm, Slack +2
AI & RAG

Feliz-Aniversario. Uses httpRequest, openAi, whatsApp, supabase. Scheduled trigger; 16 nodes.

HTTP Request, OpenAI, WhatsApp +1
AI & RAG

Fetch campaign & members from Salesforce. GPT‑4 auto‑writes a channel‑appropriate, personalised outbound message. Switch node sends via Twilio (SMS/WhatsApp), SMTP (Email). Mark each member as process

Twilio, OpenAI, Email Send +2