{ "name": "📢 Campanha WhatsApp | CRM para Evolution", "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "cronExpression", "value": "0 14 * * 2,4" } ] } }, "id": "cron-campaign-trigger", "name": "Trigger Terça/Quinta 14h", "type": "n8n-nodes-base.cron", "typeVersion": 1, "position": [240, 300] }, { "parameters": { "jsCode": "// Configurar campanha automática\nconst today = new Date();\nconst dayOfWeek = today.getDay(); // 2=terça, 4=quinta\n\n// Diferentes campanhas para diferentes dias\nconst campaigns = {\n 2: { // Terça-feira - Campanhas de Follow-up\n name: 'Follow-up Educativo',\n target_statuses: ['Novo', 'Contactado', 'Qualificado'],\n min_days_since_contact: 7,\n max_leads: 20,\n message_template: 'Olá {{name}}! 📚 Espero que esteja bem. Preparei algumas dicas valiosas sobre {{topic}}. Tem interesse em saber mais? Posso compartilhar sem compromisso! 😊',\n topics: ['otimização de processos', 'crescimento empresarial', 'automação', 'melhorias operacionais']\n },\n 4: { // Quinta-feira - Campanhas Promocionais\n name: 'Oportunidades Especiais',\n target_statuses: ['Novo', 'Qualificado', 'Em Análise'],\n min_days_since_contact: 3,\n max_leads: 15,\n message_template: '🌟 {{name}}, temos uma oportunidade especial! Nossos serviços de {{topic}} estão com condições especiais esta semana. Que tal conversarmos sobre como podemos ajudar sua empresa?',\n topics: ['consultoria especializada', 'soluções personalizadas', 'transformação digital', 'otimização de resultados']\n }\n};\n\nconst currentCampaign = campaigns[dayOfWeek] || campaigns[2]; // Default para terça\nconst randomTopic = currentCampaign.topics[Math.floor(Math.random() * currentCampaign.topics.length)];\n\nconst config = {\n campaign: currentCampaign,\n selected_topic: randomTopic,\n execution_date: today.toISOString().split('T')[0],\n timestamp: today.toISOString(),\n day_of_week: dayOfWeek\n};\n\nreturn config;" }, "id": "setup-campaign-config", "name": "Configurar Campanha", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [460, 300] }, { "parameters": { "method": "GET", "url": "https://crm.memudecore.com.br/api/leads", "authentication": "predefinedCredentialType", "nodeCredentialType": "krayin-api", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "limit", "value": "100" }, { "name": "sort", "value": "updated_at" }, { "name": "order", "value": "asc" } ] }, "options": {} }, "id": "fetch-campaign-leads", "name": "Buscar Leads para Campanha", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [680, 300], "credentials": { "krayin-api": { "id": "krayin-crm-api", "name": "Krayin CRM API" } } }, { "parameters": { "jsCode": "// Filtrar leads adequados para campanha\nconst config = $node[\"Configurar Campanha\"].json;\nconst leadsData = $node[\"Buscar Leads para Campanha\"].json;\nconst leads = leadsData.data || [];\nconst campaign = config.campaign;\n\nconst today = new Date();\nconst minDaysAgo = new Date(today.getTime() - (campaign.min_days_since_contact * 24 * 60 * 60 * 1000));\n\n// Filtrar leads elegíveis\nconst eligibleLeads = [];\n\nfor (const lead of leads) {\n // Verificar se tem telefone\n const contactPhone = lead.person?.contact_numbers?.[0]?.value;\n if (!contactPhone) continue;\n \n // Verificar status permitido\n const leadStatus = lead.stage?.name || 'Novo';\n if (!campaign.target_statuses.includes(leadStatus)) continue;\n \n // Verificar tempo desde último contato\n const lastUpdate = new Date(lead.updated_at || lead.created_at);\n if (lastUpdate > minDaysAgo) continue; // Muito recente\n \n // Verificar se não foi contactado recentemente via campanha\n // (Aqui podemos adicionar lógica para verificar histórico)\n \n // Formatar telefone para WhatsApp\n let formattedPhone = contactPhone.replace(/\\D/g, '');\n if (!formattedPhone.startsWith('55') && formattedPhone.length === 11) {\n formattedPhone = '55' + formattedPhone;\n }\n formattedPhone += '@s.whatsapp.net';\n \n // Personalizar mensagem\n const personalizedMessage = campaign.message_template\n .replace('{{name}}', lead.person?.name || 'Cliente')\n .replace('{{topic}}', config.selected_topic);\n \n eligibleLeads.push({\n lead_id: lead.id,\n lead_title: lead.title,\n contact_name: lead.person?.name || 'Cliente',\n contact_phone: contactPhone,\n whatsapp_phone: formattedPhone,\n lead_status: leadStatus,\n lead_value: lead.lead_value || 0,\n days_since_update: Math.floor((today - lastUpdate) / (1000 * 60 * 60 * 24)),\n personalized_message: personalizedMessage,\n campaign_name: campaign.name,\n topic: config.selected_topic\n });\n \n // Limitar número de leads\n if (eligibleLeads.length >= campaign.max_leads) break;\n}\n\nconst result = {\n total_leads_checked: leads.length,\n eligible_leads_found: eligibleLeads.length,\n campaign_config: campaign,\n leads_for_campaign: eligibleLeads,\n execution_summary: {\n campaign_name: campaign.name,\n target_topic: config.selected_topic,\n max_leads: campaign.max_leads,\n actual_leads: eligibleLeads.length\n },\n timestamp: new Date().toISOString()\n};\n\nreturn result;" }, "id": "filter-campaign-leads", "name": "Filtrar Leads Campanha", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [900, 300] }, { "parameters": { "conditions": { "number": [ { "value1": "={{$node[\"Filtrar Leads Campanha\"].json[\"eligible_leads_found\"]}}", "operation": "equal", "value2": 0 } ] } }, "id": "has-leads-campaign", "name": "Tem Leads p/ Campanha?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [1120, 300] }, { "parameters": { "fieldToSplitOut": "leads_for_campaign", "options": {} }, "id": "split-campaign-leads", "name": "Dividir Leads Campanha", "type": "n8n-nodes-base.splitOut", "typeVersion": 1, "position": [1340, 200] }, { "parameters": { "method": "POST", "url": "https://evolution.memudecore.com.br/message/sendText/default", "authentication": "predefinedCredentialType", "nodeCredentialType": "evolution-api", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ { "name": "number", "value": "={{$node[\"Dividir Leads Campanha\"].json[\"whatsapp_phone\"]}}" }, { "name": "text", "value": "={{$node[\"Dividir Leads Campanha\"].json[\"personalized_message\"]}}" } ] }, "options": {} }, "id": "send-campaign-message", "name": "Enviar Mensagem Campanha", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [1560, 200], "credentials": { "evolution-api": { "id": "evolution-whatsapp-api", "name": "Evolution WhatsApp API" } } }, { "parameters": { "jsCode": "// Aguardar 3 segundos entre mensagens para respeitar limites\nreturn new Promise(resolve => {\n setTimeout(() => {\n resolve({ waited: true, timestamp: new Date().toISOString() });\n }, 3000);\n});" }, "id": "wait-between-campaign-messages", "name": "Aguardar 3s", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [1780, 200] }, { "parameters": { "jsCode": "// Log detalhado da campanha enviada\nconst leadData = $node[\"Dividir Leads Campanha\"].json;\nconst sendResult = $node[\"Enviar Mensagem Campanha\"].json;\n\nconst logEntry = {\n timestamp: new Date().toISOString(),\n action: 'CAMPAIGN_MESSAGE_SENT',\n campaign_name: leadData.campaign_name,\n topic: leadData.topic,\n lead_id: leadData.lead_id,\n contact_name: leadData.contact_name,\n contact_phone: leadData.contact_phone,\n lead_status: leadData.lead_status,\n days_since_update: leadData.days_since_update,\n message_sent: leadData.personalized_message,\n whatsapp_response: sendResult,\n success: sendResult?.status === 'pending' || sendResult?.id ? true : false,\n error: sendResult?.error || null\n};\n\nreturn logEntry;" }, "id": "log-campaign-send", "name": "Log Envio Campanha", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [2000, 200] }, { "parameters": { "mode": "append", "fileName": "/tmp/whatsapp-campaigns-log.txt", "fileContent": "={{JSON.stringify($node[\"Log Envio Campanha\"].json, null, 2)}}\n---\n" }, "id": "save-campaign-log", "name": "Salvar Log Campanha", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [2220, 200] }, { "parameters": { "jsCode": "// Gerar resumo quando não há leads elegíveis\nconst campaignData = $node[\"Filtrar Leads Campanha\"].json;\n\nconst noLeadsLog = {\n timestamp: new Date().toISOString(),\n action: 'CAMPAIGN_NO_ELIGIBLE_LEADS',\n campaign_name: campaignData.campaign_config.name,\n total_leads_checked: campaignData.total_leads_checked,\n eligible_leads_found: 0,\n target_statuses: campaignData.campaign_config.target_statuses,\n min_days_requirement: campaignData.campaign_config.min_days_since_contact,\n status: 'NO_LEADS_FOUND'\n};\n\nreturn noLeadsLog;" }, "id": "log-no-leads", "name": "Log Sem Leads", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [1340, 400] }, { "parameters": { "mode": "append", "fileName": "/tmp/whatsapp-campaigns-log.txt", "fileContent": "={{JSON.stringify($node[\"Log Sem Leads\"].json, null, 2)}}\n---\n" }, "id": "save-no-leads-log", "name": "Salvar Log Sem Leads", "type": "n8n-nodes-base.writeFile", "typeVersion": 1, "position": [1560, 400] } ], "connections": { "Trigger Terça/Quinta 14h": { "main": [ [ { "node": "Configurar Campanha", "type": "main", "index": 0 } ] ] }, "Configurar Campanha": { "main": [ [ { "node": "Buscar Leads para Campanha", "type": "main", "index": 0 } ] ] }, "Buscar Leads para Campanha": { "main": [ [ { "node": "Filtrar Leads Campanha", "type": "main", "index": 0 } ] ] }, "Filtrar Leads Campanha": { "main": [ [ { "node": "Tem Leads p/ Campanha?", "type": "main", "index": 0 } ] ] }, "Tem Leads p/ Campanha?": { "main": [ [ { "node": "Log Sem Leads", "type": "main", "index": 0 } ], [ { "node": "Dividir Leads Campanha", "type": "main", "index": 0 } ] ] }, "Dividir Leads Campanha": { "main": [ [ { "node": "Enviar Mensagem Campanha", "type": "main", "index": 0 } ] ] }, "Enviar Mensagem Campanha": { "main": [ [ { "node": "Aguardar 3s", "type": "main", "index": 0 } ] ] }, "Aguardar 3s": { "main": [ [ { "node": "Log Envio Campanha", "type": "main", "index": 0 } ] ] }, "Log Envio Campanha": { "main": [ [ { "node": "Salvar Log Campanha", "type": "main", "index": 0 } ] ] }, "Log Sem Leads": { "main": [ [ { "node": "Salvar Log Sem Leads", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": {}, "versionId": "1", "meta": { "instanceId": "campaign-whatsapp" }, "id": "7", "tags": [ "Campanha", "WhatsApp", "CRM", "Marketing", "Sem Slack" ] }