{
  "name": "Agent 8: Focused Leads (Sync + Reminder)",
  "description": null,
  "active": false,
  "nodes": [
    {
      "parameters": {},
      "id": "fs_manual",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -608,
        208
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 10 * * 1-5"
            }
          ]
        }
      },
      "id": "fs_sched",
      "name": "Daily 10 AM IST",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        -608,
        400
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "outreach_log",
        "returnAll": true,
        "filters": {
          "conditions": [
            {
              "keyName": "reply_received",
              "condition": "eq",
              "keyValue": "true"
            }
          ]
        }
      },
      "id": "fs_pros",
      "name": "Fetch Replied Prospects",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        -384,
        304
      ],
      "alwaysOutputData": true,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "focused_leads",
        "returnAll": true
      },
      "id": "fs_foc",
      "name": "Fetch Existing Focused",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        -160,
        304
      ],
      "alwaysOutputData": true,
      "executeOnce": true,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "\nconst existing = new Set(\n  $('Fetch Existing Focused').all().map(i => (i.json.company || '').toLowerCase().trim())\n);\nreturn $('Fetch Replied Prospects').all().filter(i => {\n  const f = i.json;\n  const co = (f.company || '').toLowerCase().trim();\n  return co && !existing.has(co);\n}).map(i => {\n  const f = i.json;\n  return { json: {\n    id: i.json.id,\n    Company:          f.company        || '',\n    Website:          f.website        || '',\n    City:             f.city           || '',\n    Country:          f.country        || '',\n    Niche:            f.niche          || '',\n    Email:            f.to_email || f.email || '',\n    Alt_Email:        f.alt_email_found || f.alt_email || '',\n    Email_Status:     f.email_status   || 'valid',\n    Founder_Name:     f.founder_name   || '',\n    Founder_LinkedIn: f.linkedin || f.founder_linkedin || '',\n    SEO_Pain_Points:  f.pain_points || f.seo_pain_points || '',\n    Premium_Signals:  f.premium_signals  || '',\n    Premium_Fit:      f.premium_fit      || '',\n  }};\n});\n"
      },
      "id": "fs_filter",
      "name": "Filter New Only",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        64,
        304
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst d = $('Filter New Only').item.json;\nconst log = ($json && $json.id) ? $json : {};\n\nconst email_use = d.Email_Status === 'bounced' ? (d.Alt_Email || d.Email) : d.Email;\n\nconst prompt = `You are Manvendra Singh, founder of Meraku Media (premium elder-care SEO & growth agency; clients pay Rs 50-70K/month). A prospect just REPLIED to your cold outreach. Assess if they deserve a personal manual follow-up and give me the ammo to close them.\n\nPROSPECT:\n- Company: ${d.Company}\n- City: ${d.City}, ${d.Country}\n- Niche: ${d.Niche}\n- Website: ${d.Website}\n- Premium Fit: ${d.Premium_Fit}\n- Premium Signals: ${d.Premium_Signals || '(not recorded)'}\n- SEO Pain Points: ${d.SEO_Pain_Points || '(not recorded)'}\n\nOUTREACH HISTORY:\n- Email Subject: ${log.email_subject || '(unknown)'}\n- Quality Score: ${log.quality_score || 'n/a'}/10\n- Pain Points captured: ${log.pain_points || '(not recorded)'}\n\nGive me:\n1. WHY they are worth my personal manual time (2-3 specific sentences citing their signals, their reply, their budget signals)\n2. HOW Meraku can specifically help them win more premium families (2-3 sentences — concrete, tied to their actual gaps)\n3. ONE fresh personal outreach idea (e.g. a specific angle, hook, or LinkedIn move — 1-2 sentences)\n4. should_add: true unless this prospect clearly has no budget or is outside our niche\n\nReturn ONLY valid JSON, no markdown:\n{\"why_hot\":\"...\",\"how_i_can_help\":\"...\",\"first_idea\":\"...\",\"should_add\":true}`;\n\nreturn { json: { ...d, email_use, log_pain_points: log.pain_points || '', email_subject: log.email_subject || '', quality_score: log.quality_score || 0, prompt } };\n"
      },
      "id": "fs_prompt",
      "name": "Build Enrichment Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        512,
        304
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://moviesbar1-resource.openai.azure.com/openai/v1/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ {\"model\":\"gpt-5.4-2\",\"messages\":[{\"role\":\"user\",\"content\":$json.prompt}],\"max_completion_tokens\":4096} }}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 2000
            }
          },
          "timeout": 120000
        }
      },
      "id": "fs_kimi",
      "name": "GPT — Assess Fit",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        736,
        304
      ],
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 3000,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "\nconst srcItems = $('Build Enrichment Prompt').all();\nconst kimiItems = $input.all();\nconst today = new Date().toISOString().split('T')[0];\nconst out = [];\n\nfor (let i = 0; i < kimiItems.length; i++) {\n  const src = (srcItems[i] && srcItems[i].json) || {};\n  let c = kimiItems[i].json.choices?.[0]?.message?.content || '';\n  const f = c.match(/```(?:json)?\\s*([\\s\\S]*?)```/); if (f) c = f[1].trim();\n  let p = {}; try { p = JSON.parse(c.trim()); } catch (e) { continue; }\n\n  if (p.should_add === false) continue;\n  if (!p.why_hot && !p.how_i_can_help) continue;\n\n  const pain = [src.SEO_Pain_Points, src.log_pain_points].filter(Boolean).join('\\n\\n') || '';\n\n  out.push({ json: {\n    Company:         src.Company,\n    Website:         src.Website,\n    City:            src.City,\n    Email:           src.email_use,\n    LinkedIn:        src.Founder_LinkedIn,\n    Why_Hot:         p.why_hot || src.Premium_Signals || '',\n    Pain_Points:     pain,\n    How_I_Can_Help:  p.how_i_can_help || '',\n    Reachout_Ideas:  `[${today}] ${p.first_idea || ''}`,\n    Outreach_Status: 'to_contact',\n    Next_Followup:   today,\n    Last_Updated:    today,\n  }});\n}\nreturn out;\n"
      },
      "id": "fs_parse",
      "name": "Parse & Gate",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        304
      ]
    },
    {
      "parameters": {
        "tableId": "focused_leads",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "company",
              "fieldValue": "={{ $json.Company }}"
            },
            {
              "fieldId": "website",
              "fieldValue": "={{ $json.Website }}"
            },
            {
              "fieldId": "city",
              "fieldValue": "={{ $json.City }}"
            },
            {
              "fieldId": "email",
              "fieldValue": "={{ $json.Email }}"
            },
            {
              "fieldId": "linkedin",
              "fieldValue": "={{ $json.LinkedIn }}"
            },
            {
              "fieldId": "why_hot",
              "fieldValue": "={{ $json.Why_Hot }}"
            },
            {
              "fieldId": "pain_points",
              "fieldValue": "={{ $json.Pain_Points }}"
            },
            {
              "fieldId": "how_i_can_help",
              "fieldValue": "={{ $json.How_I_Can_Help }}"
            },
            {
              "fieldId": "reachout_ideas",
              "fieldValue": "={{ $json.Reachout_Ideas }}"
            },
            {
              "fieldId": "outreach_status",
              "fieldValue": "={{ $json.Outreach_Status }}"
            },
            {
              "fieldId": "next_followup",
              "fieldValue": "={{ $json.Next_Followup }}"
            },
            {
              "fieldId": "last_updated",
              "fieldValue": "={{ $json.Last_Updated }}"
            }
          ]
        }
      },
      "id": "fs_create",
      "name": "Create in Focused_Leads",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1184,
        304
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "outreach_log",
        "limit": 1,
        "matchType": "allFilters",
        "filters": {
          "conditions": [
            {
              "keyName": "reply_received",
              "condition": "eq",
              "keyValue": "true"
            },
            {
              "keyName": "company",
              "condition": "eq",
              "keyValue": "={{ $json.Company }}"
            }
          ]
        }
      },
      "id": "fs_fetch_log",
      "name": "Fetch Best Outreach Log",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        288,
        304
      ],
      "alwaysOutputData": true,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 11 * * 1-5"
            }
          ]
        }
      },
      "id": "r_t_s",
      "name": "Daily 11:00 AM IST",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        -608,
        624
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "focused_leads",
        "returnAll": true,
        "filters": {
          "conditions": [
            {
              "keyName": "converted",
              "condition": "eq",
              "keyValue": "false"
            }
          ]
        }
      },
      "id": "r_n_fetch",
      "name": "Fetch Active Focused Leads",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        -384,
        624
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst items=$input.all();\nconst today=new Date(); today.setHours(0,0,0,0);\nconst out=[];\nfor(const it of items){\n  const f=it.json;\n  const nf=f.next_followup?new Date(f.next_followup):null;\n  const due = !nf || nf<=today;\n  if(!due) continue;\n  out.push({json:{\n    id:it.json.id, company:f.company||'', website:f.website||'', city:f.city||'',\n    email:f.email||'', linkedin:f.linkedin||'', status:f.outreach_status||'to_contact',\n    count:parseInt(f.followup_count||0), pain:f.pain_points||'', help:f.how_i_can_help||'',\n    prior_ideas:f.reachout_ideas||''\n  }});\n}\nreturn out.slice(0,15);\n"
      },
      "id": "r_n_due",
      "name": "Filter Due",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -160,
        624
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst items=$input.all();\nreturn items.map(item=>{\n  const d=item.json;\n  const prompt=`I'm trying to win \"${d.company}\" (${d.website}), an elder-care brand in ${d.city}, as a premium SEO/growth client.\nCurrent status: ${d.status}, follow-up #${d.count+1}.\nTheir pain points:\\n${d.pain}\nIdeas I've already used:\\n${d.prior_ideas||'none yet'}\n\nGive me, for THIS week:\n1. \"idea\" — ONE fresh, specific, non-repetitive way to reach out or add genuine value (a new angle, a hook, something helpful I can send). Be concrete.\n2. \"followup_message\" — a short 2-3 sentence follow-up message with a proper greeting and a soft call-to-action. No emojis. Do NOT name AurumLiving or GraciasLiving — say \"several elder care brands\".\n\nReturn ONLY valid JSON: {\"idea\":\"...\",\"followup_message\":\"...\"}`;\n  return {json:{...d,prompt}};\n});\n"
      },
      "id": "r_n_idea_prompt",
      "name": "Build Idea Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        64,
        624
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://moviesbar1-resource.openai.azure.com/openai/v1/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ {\"model\":\"gpt-5.4-2\",\"messages\":[{\"role\":\"user\",\"content\":$json.prompt}],\"max_completion_tokens\":4096} }}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 2000
            }
          },
          "timeout": 280000
        }
      },
      "id": "r_n_idea",
      "name": "GPT — Fresh Angle",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        288,
        624
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "\nconst src=$('Build Idea Prompt').item.json;\nlet c=$json.choices?.[0]?.message?.content||'{}';\nconst f=c.match(/```(?:json)?\\s*([\\s\\S]*?)```/);if(f)c=f[1].trim();\nlet p={};try{p=JSON.parse(c);}catch(e){p={idea:c,followup_message:''};}\nconst today=new Date().toISOString().split('T')[0];\nconst next=new Date(Date.now()+3*86400000).toISOString().split('T')[0];\nconst statusMap=['follow_up_1','follow_up_2','follow_up_3','follow_up_3'];\nconst newStatus=statusMap[Math.min(src.count,3)];\nconst ideaLine=`[${today}] ${p.idea||''}`;\nconst merged_ideas=(src.prior_ideas?src.prior_ideas+'\\n':'')+ideaLine;\nreturn {json:{...src, idea:p.idea||'', followup_message:p.followup_message||'',\n  new_status:newStatus, next_followup:next, new_count:src.count+1, merged_ideas, today}};\n"
      },
      "id": "r_n_parse",
      "name": "Parse Idea",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        512,
        624
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "tableId": "focused_leads",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $json.id }}"
            }
          ]
        },
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "outreach_status",
              "fieldValue": "={{ $json.new_status }}"
            },
            {
              "fieldId": "followup_count",
              "fieldValue": "={{ $json.new_count }}"
            },
            {
              "fieldId": "next_followup",
              "fieldValue": "={{ $json.next_followup }}"
            },
            {
              "fieldId": "reachout_ideas",
              "fieldValue": "={{ $json.merged_ideas }}"
            },
            {
              "fieldId": "last_updated",
              "fieldValue": "={{ $json.today }}"
            }
          ]
        }
      },
      "id": "r_n_update",
      "name": "Airtable — Update Lead",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        736,
        624
      ],
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 2000,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "\nconst items=$('Parse Idea').all().filter(i=>i.json.company);\nif(!items.length) return [{json:{count:0,html:'<p>No focused leads due for follow-up today.</p>'}}];\nconst blocks=items.map(i=>{const d=i.json;\n  return `<div style=\"border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:14px\">\n  <h3 style=\"margin:0 0 4px;color:#2d3748\">${d.company} <span style=\"font-weight:normal;color:#718096\">· ${d.city} · follow-up #${d.new_count}</span></h3>\n  <p style=\"margin:4px 0\"><strong>Reach:</strong> ${d.email||'—'} | <a href=\"${d.linkedin||'#'}\">LinkedIn</a></p>\n  <p style=\"margin:8px 0 2px;color:#805ad5\"><strong>This week's move:</strong></p><div style=\"color:#444\">${d.idea}</div>\n  <p style=\"margin:8px 0 2px\"><strong>Follow-up message:</strong></p>\n  <div style=\"background:#f7fafc;border:1px solid #e2e8f0;padding:12px;border-radius:6px;white-space:pre-line\">${d.followup_message}</div>\n  </div>`;}).join('');\nconst html=`<html><body style=\"font-family:Arial,sans-serif;max-width:780px;margin:auto;padding:20px\">\n<h2 style=\"color:#2d3748\">${items.length} focused lead${items.length>1?'s':''} to follow up today</h2>\n<p>Reach out, then update their status in the Focused_Leads tab. They'll resurface in 3 days until you mark them converted.</p>\n${blocks}\n<p style=\"color:#a0aec0;font-size:12px\">Meraku Focused Leads · daily nurture</p></body></html>`;\nreturn [{json:{count:items.length,html}}];\n"
      },
      "id": "r_n_digest",
      "name": "Build Reminder Digest",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        624
      ]
    },
    {
      "parameters": {
        "sendTo": "you@yourdomain.com",
        "subject": "=[FYI] {{ $json.count }} leads to follow up today",
        "message": "={{ $json.html }}",
        "options": {
          "appendAttribution": false
        }
      },
      "id": "r_n_gmail",
      "name": "Gmail — Follow-up Reminders",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1184,
        624
      ]
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Fetch Replied Prospects",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Replied Prospects": {
      "main": [
        [
          {
            "node": "Fetch Existing Focused",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Existing Focused": {
      "main": [
        [
          {
            "node": "Filter New Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter New Only": {
      "main": [
        [
          {
            "node": "Fetch Best Outreach Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Enrichment Prompt": {
      "main": [
        [
          {
            "node": "GPT — Assess Fit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GPT — Assess Fit": {
      "main": [
        [
          {
            "node": "Parse & Gate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Gate": {
      "main": [
        [
          {
            "node": "Create in Focused_Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily 10 AM IST": {
      "main": [
        [
          {
            "node": "Fetch Replied Prospects",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Best Outreach Log": {
      "main": [
        [
          {
            "node": "Build Enrichment Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Active Focused Leads": {
      "main": [
        [
          {
            "node": "Filter Due",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Due": {
      "main": [
        [
          {
            "node": "Build Idea Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Idea Prompt": {
      "main": [
        [
          {
            "node": "GPT — Fresh Angle",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GPT — Fresh Angle": {
      "main": [
        [
          {
            "node": "Parse Idea",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Idea": {
      "main": [
        [
          {
            "node": "Airtable — Update Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Airtable — Update Lead": {
      "main": [
        [
          {
            "node": "Build Reminder Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Reminder Digest": {
      "main": [
        [
          {
            "node": "Gmail — Follow-up Reminders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily 11:00 AM IST": {
      "main": [
        [
          {
            "node": "Fetch Active Focused Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false,
    "binaryMode": "separate"
  }
}