{
  "updatedAt": "2026-03-31T06:09:02.545Z",
  "createdAt": "2026-03-31T03:55:27.175Z",
  "id": "0qxobLVFCHAgc77Q",
  "name": "Infinite Nurture - Master (Nurse Charles)",
  "description": null,
  "active": false,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "Check Every 6 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "nc-nurture-test",
        "responseMode": "onReceived",
        "options": {}
      },
      "id": "webhook-trigger",
      "name": "Manual Test Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        -150
      ],
      "webhookId": "nc-nurture-test"
    },
    {
      "parameters": {
        "jsCode": "// Define RSS feeds for Nurse Charles\nconst feeds = [\n  { url: 'https://www.fda.gov/about-fda/contact-fda/stay-informed/rss-feeds/tobacco-products/rss.xml', keywords: ['vaping', 'tobacco', 'nicotine', 'e-cigarette', 'FDA'] },\n  { url: 'https://tools.cdc.gov/api/v2/resources/media/rss', keywords: ['health', 'smoking', 'tobacco', 'nursing', 'disease'] },\n  { url: 'https://www.nursingtimes.net/feed/', keywords: ['nursing', 'burnout', 'staffing', 'ER', 'emergency', 'patient'] },\n  { url: 'https://news.google.com/rss/search?q=vaping+OR+nicotine+OR+nursing+burnout+OR+ER+staffing&hl=en-US&gl=US&ceid=US:en', keywords: ['vaping', 'nicotine', 'nursing', 'burnout', 'ER', 'staffing', 'quit smoking'] }\n];\n\nreturn feeds.map(f => ({ json: f }));"
      },
      "id": "code-feeds",
      "name": "Define RSS Feeds",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        250,
        -300
      ]
    },
    {
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {}
      },
      "id": "rss-read",
      "name": "Fetch RSS Feed",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1,
      "position": [
        500,
        -300
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// Filter articles by relevance and recency\nconst items = $input.all();\nconst feedInfo = $node['Define RSS Feeds'].json;\nconst keywords = feedInfo.keywords || [];\nconst oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n\nconst relevant = [];\n\nfor (const item of items) {\n  const data = item.json;\n  const title = (data.title || '').toLowerCase();\n  const description = (data.description || data.content || data.contentSnippet || '').toLowerCase();\n  const pubDate = data.pubDate || data.isoDate || data.date;\n  \n  if (pubDate) {\n    const articleDate = new Date(pubDate);\n    if (articleDate < oneDayAgo) continue;\n  }\n  \n  const text = title + ' ' + description;\n  const matchedKeywords = keywords.filter(kw => text.includes(kw.toLowerCase()));\n  \n  if (matchedKeywords.length > 0) {\n    relevant.push({\n      json: {\n        title: data.title || '',\n        link: data.link || '',\n        description: (data.description || data.contentSnippet || '').substring(0, 500),\n        source: data.creator || new URL(feedInfo.url).hostname,\n        pubDate: pubDate || new Date().toISOString(),\n        matchedKeywords: matchedKeywords.join(', ')\n      }\n    });\n  }\n}\n\nreturn relevant.length > 0 ? relevant.slice(0, 3) : [{ json: { skip: true } }];"
      },
      "id": "code-filter",
      "name": "Filter Relevant Articles",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        750,
        -300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "leftValue": "={{ $json.skip }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "if-has-articles",
      "name": "Has New Articles?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1000,
        -300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer 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"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model: 'gpt-4.1-mini', max_tokens: 300, messages: [{ role: 'user', content: 'Summarize this news article in 2-3 sentences for use in an email newsletter. Focus on what makes it relevant and interesting to nurses, parents, or health advocates. Be factual and concise.\\n\\nTitle: ' + $json.title + '\\n\\nDescription: ' + $json.description }] }) }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": true
            }
          }
        }
      },
      "id": "http-summarize",
      "name": "Summarize with GPT",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1250,
        -400
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format for Content Bank\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const response = item.json;\n  const body = response.body || response;\n  const summary = body.choices?.[0]?.message?.content || 'Summary unavailable';\n  const articleData = $node['Filter Relevant Articles'].json;\n  \n  results.push({\n    json: {\n      dateFound: new Date().toISOString().split('T')[0],\n      source: item.json.source || articleData?.source || 'Unknown',\n      headline: item.json.title || articleData?.title || '',\n      summary: summary,\n      keywords: item.json.matchedKeywords || articleData?.matchedKeywords || '',\n      used: 'no'\n    }\n  });\n}\n\nreturn results;"
      },
      "id": "code-format-rss",
      "name": "Format for Content Bank",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1500,
        -400
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1AbmksVFpwEIeY6xMo_wt_tVLg2XACQ9UNDUCHCOtXgo",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Sheet1",
          "mode": "list",
          "cachedResultName": "Sheet1"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Date Found": "={{ $json.dateFound }}",
            "Source": "={{ $json.source }}",
            "Headline": "={{ $json.headline }}",
            "Summary": "={{ $json.summary }}",
            "Keywords": "={{ $json.keywords }}",
            "Used": "={{ $json.used }}"
          }
        },
        "options": {}
      },
      "id": "sheets-rss-append",
      "name": "Write to Content Bank",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1750,
        -400
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "OhjizsinSISmx4Gl",
          "name": "Google Sheets OAuth2 API"
        }
      }
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://services.leadconnectorhq.com/contacts/?locationId=VMK8SyHTd8uCMgcJ7I2A&limit=100&query=",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer pit-f4efbe95-ae07-4ef7-a057-6f81185e9c83"
            },
            {
              "name": "Version",
              "value": "2021-07-28"
            }
          ]
        },
        "options": {}
      },
      "id": "http-get-contacts",
      "name": "Get Contacts from GHL",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        250,
        200
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "1saDG5fubvtvvn3lK_o4pVDLtKu4RS1Yqr8fsUEdevlM",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": 0,
          "mode": "list",
          "cachedResultName": "Sheet1"
        },
        "options": {}
      },
      "id": "sheets-send-history",
      "name": "Get Send History",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        250,
        450
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "OhjizsinSISmx4Gl",
          "name": "Google Sheets OAuth2 API"
        }
      }
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "1hu1pIKhjjxJaqQjVCNJPfe9E3iMbyQAzEPcONw7eHoY",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": 0,
          "mode": "list",
          "cachedResultName": "Sheet1"
        },
        "options": {}
      },
      "id": "sheets-campaigns",
      "name": "Get Active Campaigns",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        250,
        700
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "OhjizsinSISmx4Gl",
          "name": "Google Sheets OAuth2 API"
        }
      }
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "1AbmksVFpwEIeY6xMo_wt_tVLg2XACQ9UNDUCHCOtXgo",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": 0,
          "mode": "list",
          "cachedResultName": "Sheet1"
        },
        "options": {}
      },
      "id": "sheets-content-bank",
      "name": "Get Content Bank",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        250,
        950
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "OhjizsinSISmx4Gl",
          "name": "Google Sheets OAuth2 API"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Phase Guide for Nurse Charles\n// Source: NC Phase Guide doc (ID: 1oK4YUINbaenkul2Dic-3Hgy7Pb9rMaHO)\nreturn [{ json: { phaseGuide: `## Voice: First person as Charles. Direct, warm, clinical authority. Open with health tip, myth-bust, or ER story. Never use jargon without explaining. Sign as Nurse Charles, ER Nurse - Educator - Advocate. 37+ years, 150K TikTok.\n\n## Phases:\n- intro (sends 1-3): Welcome, origin story, credibility. Warm, personal. NO product mentions. CTA: visit site or follow socials.\n- value (sends 4-10): ER stories, nursing tips, vaping truth, health education. Teach something. NO product mentions. CTA: share or reply.\n- soft_offer (sends 11-15): Introduce free resources. Send 11: 5-Day Smoke-Free Challenge (free, nursecharlesmedia.com/challenge). Send 13: Skool Community ($9.99/mo, nursecharlesmedia.com/skool). Value-first with soft CTAs.\n- conversion (sends 16-20): Present paid products directly. Inner Circle $29.99/mo, 1:1 coaching $25/session, community $9.99/mo. Speaking engagements. Full ecosystem. CTA: clear buy/join links.\n- warm_cruise (sends 21-35): 70% value, 20% soft product mention, 10% engagement. Current events when available. Campaign blending.\n- long_game (sends 36+): 80% value, 10% product (only when relevant), 10% engagement. Re-engagement hooks if opens drop.\n\n## Products (only reference after noted phase):\n- 5-Day Smoke-Free Challenge: Free, nursecharlesmedia.com/challenge (phase 3+)\n- Skool Community: $9.99/mo, nursecharlesmedia.com/skool (phase 3+)\n- Inner Circle: $29.99/mo, nursecharlesmedia.com/skool (phase 4+)\n- 1:1 Coaching: $25/session (phase 4+)\n- Speaking: nursecharlesmedia.com/book (phase 4+)\n\n## Subject patterns: intro=curiosity/personal, value=story-driven, soft_offer=value+resource, conversion=direct/confident, cruise/long=mix+current events\n\n## Avoid: medical diagnoses, political content, disparaging other HCPs, inflated follower counts (150K not higher), consecutive product pitches` } }];"
      },
      "id": "code-phase-guide",
      "name": "Read Phase Guide",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        250,
        1200
      ]
    },
    {
      "parameters": {
        "jsCode": "// Pass-through to wait for all parallel inputs\nreturn [{ json: { ready: true } }];"
      },
      "id": "code-wait",
      "name": "Wait for All Data",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        550,
        450
      ]
    },
    {
      "parameters": {
        "jsCode": "// Determine which contacts are due for an email\nconst contacts = $node['Get Contacts from GHL'].json.contacts || $node['Get Contacts from GHL'].json.body?.contacts || [];\nconst sendHistoryItems = $node['Get Send History'].all?.() || [];\nconst campaignItems = $node['Get Active Campaigns'].all?.() || [];\nconst contentBankItems = $node['Get Content Bank'].all?.() || [];\n\n// Get Phase Guide content\nconst phaseGuideRaw = $node['Read Phase Guide'].json;\nconst phaseGuide = phaseGuideRaw.phaseGuide || '';\n\n// Build send history lookup\nconst sendHistory = {};\nfor (const item of sendHistoryItems) {\n  const row = item.json || item;\n  const email = row['Contact Email'] || '';\n  if (!email) continue;\n  if (!sendHistory[email]) {\n    sendHistory[email] = { sendCount: 0, lastSendDate: null };\n  }\n  sendHistory[email].sendCount++;\n  const ts = row['Timestamp'];\n  if (ts && (!sendHistory[email].lastSendDate || ts > sendHistory[email].lastSendDate)) {\n    sendHistory[email].lastSendDate = ts;\n  }\n}\n\n// Get active campaigns\nconst today = new Date().toISOString().split('T')[0];\nconst activeCampaigns = campaignItems\n  .map(i => i.json || i)\n  .filter(c => c.Status === 'active' && c['Promote Start'] <= today && c['Promote End'] >= today);\n\n// Get unused content\nconst unusedContent = contentBankItems\n  .map(i => i.json || i)\n  .filter(c => c.Used !== 'yes')\n  .slice(0, 3);\n\nconst phaseCadence = {\n  'intro': 3, 'value': 3, 'soft_offer': 3, 'conversion': 3,\n  'warm_cruise': 5, 'long_game': 7\n};\n\nfunction getPhase(sendCount) {\n  if (sendCount < 3) return 'intro';\n  if (sendCount < 10) return 'value';\n  if (sendCount < 15) return 'soft_offer';\n  if (sendCount < 20) return 'conversion';\n  if (sendCount < 35) return 'warm_cruise';\n  return 'long_game';\n}\n\nfunction isDue(email) {\n  const history = sendHistory[email];\n  if (!history || !history.lastSendDate) return true;\n  const phase = getPhase(history.sendCount);\n  let cadenceDays = phaseCadence[phase];\n  if (activeCampaigns.length > 0) cadenceDays = Math.min(cadenceDays, 3);\n  const lastSend = new Date(history.lastSendDate);\n  const nextDue = new Date(lastSend.getTime() + cadenceDays * 24 * 60 * 60 * 1000);\n  return new Date() >= nextDue;\n}\n\nconst dueContacts = contacts.filter(c => {\n  const email = c.email;\n  if (!email) return false;\n  const tags = c.tags || [];\n  if (tags.includes('email_unsubscribed') || tags.includes('email_bounced') || tags.includes('email_cold')) return false;\n  return isDue(email);\n});\n\nconst batch = dueContacts.slice(0, 10);\n\nif (batch.length === 0) return [{ json: { noDueContacts: true } }];\n\nreturn batch.map(contact => {\n  const email = contact.email;\n  const history = sendHistory[email] || { sendCount: 0, lastSendDate: null };\n  const phase = getPhase(history.sendCount);\n  const sendNumber = history.sendCount + 1;\n  \n  return {\n    json: {\n      contactId: contact.id,\n      email: contact.email,\n      firstName: contact.firstName || contact.first_name || 'there',\n      phase,\n      sendNumber,\n      activeCampaigns,\n      unusedContent,\n      phaseGuide,\n      isFirstCampaignEmail: activeCampaigns.length > 0 && !sendHistoryItems.some(i => {\n        const row = i.json || i;\n        return row['Contact Email'] === email && row['Campaign Blended'] && row['Campaign Blended'] !== '';\n      })\n    }\n  };\n});"
      },
      "id": "code-determine-due",
      "name": "Determine Due Contacts",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        450
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "leftValue": "={{ $json.noDueContacts }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "if-has-contacts",
      "name": "Any Due Contacts?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1050,
        450
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer 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"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model: 'gpt-4.1', max_tokens: 2000, messages: [{ role: 'system', content: 'You are the AI email marketer for Nurse Charles (nursecharlesmedia.com). You write emails exactly as Charles would -- direct, warm, clinical authority. Always respond with valid JSON only, no markdown.' }, { role: 'user', content: '## Subscriber Info\\n- First name: ' + $json.firstName + '\\n- Phase: ' + $json.phase + '\\n- Send number: ' + $json.sendNumber + '\\n\\n## Phase Guide (from doc)\\n' + ($json.phaseGuide || 'No phase guide loaded. Use defaults: intro=welcome/credibility, value=ER stories/tips, soft_offer=free resources, conversion=paid products, warm_cruise/long_game=evergreen value.') + '\\n\\n## Active Campaigns\\n' + JSON.stringify($json.activeCampaigns || []) + '\\n\\n## Recent News (use if relevant)\\n' + JSON.stringify(($json.unusedContent || []).map(c => c.Headline + ': ' + c.Summary).slice(0, 2)) + '\\n\\n## Output Format (JSON only)\\n{\"subject\": \"...\", \"preheader\": \"...\", \"body_html\": \"<full email body HTML using this structure: greeting, hook/story, main content, CTA if appropriate for phase, sign-off as Nurse Charles>\", \"content_source\": \"evergreen|current_event|campaign\"}' }] }) }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": true
            }
          },
          "timeout": 30000
        }
      },
      "id": "http-generate-email",
      "name": "Generate Email with GPT",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1300,
        350
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse AI response and build branded HTML email\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const response = item.json;\n  const body = response.body || response;\n  const aiText = body.choices?.[0]?.message?.content || body.content?.[0]?.text || '{}';\n  \n  let parsed;\n  try {\n    const jsonMatch = aiText.match(/\\{[\\s\\S]*\\}/);\n    parsed = JSON.parse(jsonMatch ? jsonMatch[0] : aiText);\n  } catch (e) {\n    parsed = { subject: 'From Nurse Charles', preheader: '', body_html: aiText, content_source: 'evergreen' };\n  }\n  \n  const contactData = $node['Determine Due Contacts'].json;\n  \n  const brandedHtml = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>${parsed.subject}</title>\n<style>\n  body { margin: 0; padding: 0; background-color: #080c16; font-family: 'Helvetica Neue', Arial, sans-serif; }\n  .email-wrapper { max-width: 600px; margin: 0 auto; background: #0B0F1A; }\n  .header { background: linear-gradient(135deg, #0B0F1A, #151C2E); padding: 30px 40px; text-align: center; border-bottom: 2px solid rgba(96,247,250,0.15); }\n  .header h1 { color: #60f7fa; font-family: 'Bebas Neue', Arial, sans-serif; font-size: 28px; margin: 0; font-weight: 600; letter-spacing: 0.05em; }\n  .header p { color: #5a9ea3; font-size: 14px; margin: 5px 0 0; }\n  .body-content { padding: 35px 40px; color: #e2e8f0; line-height: 1.7; font-size: 16px; }\n  .body-content h2 { color: #ffffff; font-size: 20px; margin-top: 0; }\n  .body-content p { margin: 0 0 18px; }\n  .body-content a { color: #60f7fa; }\n  .body-content strong { color: #ffffff; }\n  .body-content em { font-style: italic; }\n  .highlight-box { background: rgba(96,247,250,0.06); border-left: 3px solid #60f7fa; padding: 18px 22px; margin: 22px 0; border-radius: 0 6px 6px 0; }\n  .cta-button { display: inline-block; background: linear-gradient(135deg, #43797d, #5a9ea3); color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 6px; font-weight: 600; font-size: 16px; margin: 10px 0; }\n  .signature { border-top: 1px solid rgba(96,247,250,0.08); padding-top: 20px; margin-top: 10px; }\n  .signature p { margin: 0 0 4px; font-size: 15px; color: #e2e8f0; }\n  .footer { background: #080c16; padding: 25px 40px; text-align: center; border-top: 1px solid rgba(96,247,250,0.08); }\n  .social-links { margin: 0 0 15px; }\n  .social-links a { color: #5a9ea3; text-decoration: none; margin: 0 12px; font-size: 14px; }\n  .footer p { color: #64748b; font-size: 12px; margin: 5px 0; }\n  .footer a { color: #5a9ea3; text-decoration: underline; }\n</style>\n</head>\n<body>\n<div style=\"display:none;max-height:0;overflow:hidden;\">${parsed.preheader || ''}</div>\n<table width=\"100%\" style=\"background:#080c16;\"><tr><td align=\"center\" style=\"padding:16px;\">\n<div class=\"email-wrapper\">\n  <div class=\"header\">\n    <h1>NURSE CHARLES</h1>\n    <p>Real Talk from the ER &bull; 37+ Years Strong</p>\n  </div>\n  <div class=\"body-content\">\n    ${parsed.body_html}\n  </div>\n  <div class=\"footer\">\n    <div class=\"social-links\">\n      <a href=\"https://www.tiktok.com/@nursecharlesmedia\">TikTok</a>\n      <a href=\"https://www.instagram.com/nursecharlesmedia\">Instagram</a>\n      <a href=\"https://www.youtube.com/@NurseCharles\">YouTube</a>\n    </div>\n    <p><a href=\"https://nursecharlesmedia.com\">NurseCharlesMedia.com</a></p>\n    <p>&copy; 2026 Nurse Charles Media. All rights reserved.</p>\n    <p><a href=\"{{{unsubscribe_url}}}\">Unsubscribe</a></p>\n  </div>\n</div>\n</td></tr></table>\n</body>\n</html>`;\n\n  results.push({\n    json: {\n      ...contactData,\n      subject: parsed.subject,\n      preheader: parsed.preheader || '',\n      body_html: brandedHtml,\n      content_source: parsed.content_source || 'evergreen',\n      campaignBlended: (contactData.activeCampaigns || []).length > 0 ? contactData.activeCampaigns[0]['Campaign Name'] || 'yes' : ''\n    }\n  });\n}\n\nreturn results;"
      },
      "id": "code-build-html",
      "name": "Build Branded HTML",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1550,
        350
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "leftValue": "={{ $json.isFirstCampaignEmail }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "if-needs-approval",
      "name": "Needs Approval?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1800,
        350
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.resend.com/emails",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer re_MGzbun88_N9BQXp9dCQTqA9pTjfv91cJV"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ from: 'Nurse Charles <hello@nursecharlesmedia.com>', to: ['bryce@emersonnorth.com'], subject: '[APPROVAL NEEDED] ' + $json.subject, html: '<div style=\"background:#222;color:#fff;padding:20px;margin-bottom:20px;font-family:Arial;\"><h2 style=\"color:#60f7fa;\">APPROVAL DRAFT</h2><p>Contact: ' + $json.email + ' | Phase: ' + $json.phase + ' | Send #' + $json.sendNumber + '</p><p>Campaign: ' + ($json.campaignBlended || 'none') + '</p><p style=\"color:#5a9ea3;\">Reply APPROVE to send, or REJECT with notes.</p></div><hr>' + $json.body_html }) }}",
        "options": {}
      },
      "id": "http-send-approval",
      "name": "Send Approval Draft to Bryce",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2050,
        250
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.resend.com/emails",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer re_MGzbun88_N9BQXp9dCQTqA9pTjfv91cJV"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ from: 'Nurse Charles <hello@nursecharlesmedia.com>', to: [$json.email], subject: $json.subject, html: $json.body_html }) }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": true
            }
          }
        }
      },
      "id": "http-send-resend",
      "name": "Send via Resend",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2050,
        450
      ]
    },
    {
      "parameters": {
        "jsCode": "// Log send to history sheet\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const data = item.json;\n  const responseBody = data.body || data;\n  const resendId = responseBody.id || '';\n  const contactData = $node['Build Branded HTML'].json;\n  \n  results.push({\n    json: {\n      timestamp: new Date().toISOString(),\n      contactEmail: contactData.email,\n      contactId: contactData.contactId,\n      phase: contactData.phase,\n      sendNumber: contactData.sendNumber,\n      subject: contactData.subject,\n      campaignBlended: contactData.campaignBlended || '',\n      contentSource: contactData.content_source || 'evergreen',\n      resendMessageId: resendId,\n      status: 'sent'\n    }\n  });\n}\n\nreturn results;"
      },
      "id": "code-log",
      "name": "Prep Send Log",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2300,
        450
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1saDG5fubvtvvn3lK_o4pVDLtKu4RS1Yqr8fsUEdevlM",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Sheet1",
          "mode": "list",
          "cachedResultName": "Sheet1"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Timestamp": "={{ $json.timestamp }}",
            "Contact Email": "={{ $json.contactEmail }}",
            "Contact ID": "={{ $json.contactId }}",
            "Phase": "={{ $json.phase }}",
            "Send Number": "={{ $json.sendNumber }}",
            "Subject": "={{ $json.subject }}",
            "Campaign Blended": "={{ $json.campaignBlended }}",
            "Content Source": "={{ $json.contentSource }}",
            "Resend Message ID": "={{ $json.resendMessageId }}",
            "Status": "={{ $json.status }}"
          }
        },
        "options": {}
      },
      "id": "sheets-log-send",
      "name": "Log to Send History",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        2550,
        450
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "OhjizsinSISmx4Gl",
          "name": "Google Sheets OAuth2 API"
        }
      }
    }
  ],
  "connections": {
    "Check Every 6 Hours": {
      "main": [
        [
          {
            "node": "Define RSS Feeds",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Contacts from GHL",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Send History",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Active Campaigns",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Content Bank",
            "type": "main",
            "index": 0
          },
          {
            "node": "Read Phase Guide",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Test Trigger": {
      "main": [
        [
          {
            "node": "Define RSS Feeds",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Contacts from GHL",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Send History",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Active Campaigns",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Content Bank",
            "type": "main",
            "index": 0
          },
          {
            "node": "Read Phase Guide",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Define RSS Feeds": {
      "main": [
        [
          {
            "node": "Fetch RSS Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch RSS Feed": {
      "main": [
        [
          {
            "node": "Filter Relevant Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Relevant Articles": {
      "main": [
        [
          {
            "node": "Has New Articles?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has New Articles?": {
      "main": [
        [
          {
            "node": "Summarize with GPT",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Summarize with GPT": {
      "main": [
        [
          {
            "node": "Format for Content Bank",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format for Content Bank": {
      "main": [
        [
          {
            "node": "Write to Content Bank",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Contacts from GHL": {
      "main": [
        [
          {
            "node": "Wait for All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Send History": {
      "main": [
        [
          {
            "node": "Wait for All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Active Campaigns": {
      "main": [
        [
          {
            "node": "Wait for All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Content Bank": {
      "main": [
        [
          {
            "node": "Wait for All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Phase Guide": {
      "main": [
        [
          {
            "node": "Wait for All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for All Data": {
      "main": [
        [
          {
            "node": "Determine Due Contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Determine Due Contacts": {
      "main": [
        [
          {
            "node": "Any Due Contacts?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any Due Contacts?": {
      "main": [
        [
          {
            "node": "Generate Email with GPT",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Generate Email with GPT": {
      "main": [
        [
          {
            "node": "Build Branded HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Branded HTML": {
      "main": [
        [
          {
            "node": "Needs Approval?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Needs Approval?": {
      "main": [
        [
          {
            "node": "Send Approval Draft to Bryce",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send via Resend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send via Resend": {
      "main": [
        [
          {
            "node": "Prep Send Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep Send Log": {
      "main": [
        [
          {
            "node": "Log to Send History",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "staticData": {
    "node:Check Every 6 Hours": {
      "recurrenceRules": [
        6
      ]
    }
  },
  "meta": null,
  "pinData": null,
  "versionId": "64cfa834-e21f-4d08-a234-6c5df01c3746",
  "activeVersionId": null,
  "versionCounter": 53,
  "triggerCount": 2,
  "shared": [
    {
      "updatedAt": "2026-03-31T03:55:27.177Z",
      "createdAt": "2026-03-31T03:55:27.177Z",
      "role": "workflow:owner",
      "workflowId": "0qxobLVFCHAgc77Q",
      "projectId": "91dLj8Hg37i136qG",
      "project": {
        "updatedAt": "2026-03-22T06:53:28.112Z",
        "createdAt": "2026-02-12T18:32:53.056Z",
        "id": "91dLj8Hg37i136qG",
        "name": "Bryce Folsom <bfolsom@emersonnorth.com>",
        "type": "personal",
        "icon": null,
        "description": null,
        "creatorId": "17d3676f-3e74-4586-8363-5c1f4d237ed7"
      }
    }
  ],
  "tags": [],
  "activeVersion": null
}