How to Build a Vertical Prospecting Engine with n8n (Free Template)

How to Build a Vertical Prospecting Engine with n8n (Free Template)

You built a product. Now you need to find the right market. Testing one vertical at a time is slow and expensive. This n8n workflow solves that by automating vertical discovery across 10-30 markets simultaneously. You'll identify adjacent verticals with AI, generate customized landing pages for each, prospect decision-makers with Exa.ai, and measure engagement to find product-market fit in weeks instead of months.

The Problem: Manual Market Validation Kills Momentum

Most founders test product-market fit by manually targeting one vertical at a time. You build custom messaging, create landing pages, research prospects, and run outreach campaigns. After weeks of work, you discover the vertical doesn't convert. Then you start over with a new vertical.

Current challenges:

  • Testing 10 verticals manually takes 6-12 months of full-time work
  • Each vertical requires custom landing pages, prospect research, and messaging
  • No systematic way to compare engagement signals across markets
  • Guessing which verticals will work instead of measuring actual demand

Business impact:

  • Time spent: 40+ hours per vertical for setup and testing
  • Opportunity cost: Missing better markets while focused on wrong verticals
  • Cash burn: Paying for ads and tools across multiple failed experiments
  • Decision paralysis: No clear data on which vertical to scale

The Solution Overview

This n8n workflow turns product validation into a systematic process. AI identifies 10-30 adjacent verticals where your product solves similar problems. The system generates unique landing pages for each vertical, stores them in Supabase, prospects decision-makers with Exa.ai, and runs targeted cold email campaigns. You measure engagement across all verticals simultaneously and identify the 2-3 markets with the strongest product-market fit signals.

The workflow uses Claude for vertical identification and landing page generation, Supabase as your database, Exa.ai for prospect discovery, and email automation for outreach. Each vertical gets tested in parallel, giving you comparative data within weeks.

What You'll Build

This vertical prospecting engine automates the entire market validation process from vertical identification through prospect outreach.

Component Technology Purpose
Vertical Discovery Claude AI Identifies 10-30 adjacent markets for your product
Landing Page Generation Claude AI + Custom Code Creates vertical-specific pages with tailored messaging
Database Supabase Stores landing pages, prospects, and engagement metrics
Prospect Research Exa.ai Finds decision-makers in each vertical
Email Outreach SMTP/Email Service Sends personalized cold emails to prospects
Analytics Engine n8n Function Nodes Tracks engagement and identifies winning verticals

Prerequisites

Before starting, ensure you have:

  • n8n instance (cloud or self-hosted)
  • Claude API key (Anthropic account)
  • Supabase account with database configured
  • Exa.ai API access
  • Email service (SMTP or SendGrid/Mailgun)
  • Domain for hosting landing pages
  • Basic JavaScript knowledge for Function nodes

Step 1: Set Up Vertical Discovery with AI

The workflow starts by analyzing your product and identifying adjacent verticals where it could provide value. If you built a sales training tool for real estate photographers, AI suggests other service-based sales roles: HVAC sales, roofing consultants, medical device reps, insurance agents, and 20+ more.

Configure the Claude AI Node

  1. Add an HTTP Request node to call Claude's API
  2. Set the endpoint to https://api.anthropic.com/v1/messages
  3. Configure authentication with your Anthropic API key in headers
  4. Build a prompt that describes your product and asks for vertical suggestions

Node configuration:

{
  "model": "claude-3-5-sonnet-20241022",
  "max_tokens": 4000,
  "messages": [
    {
      "role": "user",
      "content": "Product: [Your product description]. Identify 20-30 adjacent verticals where this product solves similar problems. For each vertical, provide: industry name, typical pain points, decision-maker titles, and why this product fits."
    }
  ]
}

Why this works:
Claude analyzes your product's core value proposition and maps it to industries with similar workflows, pain points, and buying behaviors. The AI identifies patterns in who benefits from your solution, not just obvious competitors.

Parse and structure the response:

Add a Function node to extract the vertical list from Claude's response and format it as structured data. Each vertical becomes a record with fields for industry name, pain points, target personas, and customization notes.

Step 2: Generate Vertical-Specific Landing Pages

Each vertical needs a landing page that speaks directly to their pain points using industry-specific language. A real estate photographer sees "Close more listing appointments." An HVAC salesperson sees "Win more installation contracts."

Configure Landing Page Generation

  1. Loop through each vertical from Step 1 using a Split in Batches node
  2. For each vertical, call Claude again to generate landing page content
  3. Include the vertical's pain points, target persona, and your product's core features
  4. Generate headline, subheadline, benefit bullets, social proof, and CTA copy

Prompt structure for landing pages:

const vertical = $input.item.json.vertical;
const painPoints = $input.item.json.painPoints;
const persona = $input.item.json.persona;

const prompt = `Create a landing page for ${vertical} professionals. 
Pain points: ${painPoints}
Target persona: ${persona}
Product: [Your product description]

Generate:
- Headline (8-12 words, speaks to main pain point)
- Subheadline (15-20 words, explains solution)
- 5 benefit bullets (specific to ${vertical})
- Social proof section (testimonial format for ${vertical})
- CTA button text and supporting copy

Use ${vertical} industry terminology. Make it feel like it was built specifically for them.`;

Store in Supabase:

Connect a Supabase node to insert each landing page into your database. Store the vertical name, all copy elements, creation date, and a unique URL slug. This makes it easy to update content and track which pages perform best.

Database schema:

CREATE TABLE landing_pages (
  id UUID PRIMARY KEY,
  vertical_name TEXT,
  url_slug TEXT UNIQUE,
  headline TEXT,
  subheadline TEXT,
  benefits JSONB,
  social_proof TEXT,
  cta_text TEXT,
  created_at TIMESTAMP,
  engagement_score DECIMAL
);

Step 3: Prospect Decision-Makers with Exa.ai

Now you need people to send to these landing pages. Exa.ai finds decision-makers in each vertical based on job titles, company characteristics, and online presence.

Configure Exa.ai Integration

  1. Add an HTTP Request node for Exa.ai's API
  2. Set endpoint to https://api.exa.ai/search
  3. Build search queries for each vertical using job titles and industry keywords
  4. Request 20-30 prospects per vertical

Search query structure:

{
  "query": "{{$json.vertical}} {{$json.decisionMakerTitle}} email contact",
  "num_results": 25,
  "type": "neural",
  "contents": {
    "text": true
  },
  "include_domains": ["linkedin.com"],
  "category": "company"
}

Extract and enrich prospect data:

Use a Function node to parse Exa.ai results and extract names, titles, companies, and LinkedIn profiles. Add another HTTP Request node to find email addresses using an email finder service (Hunter.io, Apollo, or similar).

Store prospects in Supabase:

CREATE TABLE prospects (
  id UUID PRIMARY KEY,
  vertical_id UUID REFERENCES landing_pages(id),
  name TEXT,
  title TEXT,
  company TEXT,
  email TEXT,
  linkedin_url TEXT,
  found_date TIMESTAMP,
  outreach_status TEXT
);

Step 4: Automate Cold Email Campaigns

Each prospect receives a personalized email that drives them to their vertical-specific landing page. The email references their industry, pain points, and includes the customized landing page URL.

Configure Email Node

  1. Add an SMTP or email service node (SendGrid, Mailgun, etc.)
  2. Loop through prospects for each vertical
  3. Generate personalized email copy using Claude
  4. Include the vertical-specific landing page URL with UTM parameters

Email template structure:

const prospect = $input.item.json;
const landingPage = $input.item.json.landingPageUrl;

const emailPrompt = `Write a cold email to ${prospect.name}, a ${prospect.title} at ${prospect.company}.

Context:
- Industry: ${prospect.vertical}
- Pain point: ${prospect.painPoint}
- Solution: [Your product]
- Landing page: ${landingPage}

Requirements:
- Subject line (5-7 words)
- 3-4 short sentences
- One specific pain point for ${prospect.vertical}
- Clear CTA to visit landing page
- Professional but conversational tone`;

Track email engagement:

Add UTM parameters to landing page URLs so you can track which verticals generate the most clicks. Store email open rates, click rates, and reply rates in Supabase for each vertical.

Workflow Architecture Overview

This workflow consists of 24 nodes organized into 4 main sections:

  1. Vertical discovery (Nodes 1-6): Claude identifies adjacent markets, parses responses, structures data
  2. Landing page generation (Nodes 7-14): Loops through verticals, generates custom copy, stores in Supabase
  3. Prospect research (Nodes 15-20): Exa.ai finds decision-makers, enriches with emails, stores in database
  4. Email outreach (Nodes 21-24): Generates personalized emails, sends campaigns, tracks engagement

Execution flow:

  • Trigger: Manual execution or scheduled weekly
  • Average run time: 15-25 minutes for 20 verticals
  • Key dependencies: Claude API, Supabase database, Exa.ai, email service

Critical nodes:

  • HTTP Request (Claude): Handles vertical identification and landing page generation
  • Supabase nodes: Store and retrieve landing pages, prospects, engagement data
  • Split in Batches: Processes verticals and prospects in parallel
  • Function nodes: Parse API responses, format data, calculate engagement scores

The complete n8n workflow JSON template is available at the bottom of this article.

Key Configuration Details

Claude API Settings

Required fields:

  • API Key: Your Anthropic API key
  • Model: claude-3-5-sonnet-20241022 (best for creative content generation)
  • Max tokens: 4000 (sufficient for landing page copy)
  • Temperature: 0.7 (balances creativity with consistency)

Common issues:

  • Using claude-instant instead of Sonnet → Lower quality landing page copy
  • Token limit too low → Truncated landing page content
  • Missing system prompt → Generic copy that doesn't match vertical

Supabase Configuration

Connection settings:

  • Host: Your Supabase project URL
  • API Key: Service role key (not anon key) for write access
  • Table names: landing_pages, prospects, engagement_metrics

Why this approach:
Supabase provides a PostgreSQL database with a REST API, making it easy to store structured data from n8n. The service role key allows the workflow to insert and update records without authentication issues. Using separate tables for landing pages and prospects enables you to track relationships and calculate engagement scores per vertical.

Variables to customize:

  • verticalCount: Adjust from 10-30 based on how many markets you want to test
  • prospectsPerVertical: Change from 20-30 based on outreach volume capacity
  • emailDelay: Set delay between emails to avoid spam filters (recommended: 30-60 seconds)

Testing & Validation

Test vertical discovery:
Run the workflow with your product description and review the AI-generated vertical list. Verify that suggested verticals make sense and have clear pain point mappings. If verticals are too broad or unrelated, refine your product description prompt.

Validate landing page quality:
Generate 3-5 test landing pages and review them for industry-specific language. Check that headlines address vertical-specific pain points, not generic benefits. Test that all copy elements are present (headline, subheadline, benefits, social proof, CTA).

Verify prospect data:
Run Exa.ai searches for 2-3 verticals and inspect the results. Confirm that job titles match decision-maker profiles. Validate email addresses using an email verification service before sending campaigns.

Test email delivery:
Send test emails to your own address for each vertical. Check that personalization works, landing page URLs are correct, and UTM parameters track properly. Verify emails don't trigger spam filters by testing with Mail-Tester.com.

Deployment Considerations

Production Deployment Checklist

Area Requirement Why It Matters
Error Handling Retry logic on API failures with exponential backoff Claude and Exa.ai can timeout; prevents data loss
Rate Limiting Delay nodes between API calls (2-3 seconds) Avoids hitting API rate limits and getting blocked
Email Warmup Start with 20-30 emails/day, increase gradually Cold domains need warmup to avoid spam folders
Database Backups Daily Supabase backups enabled Protects landing page content and prospect data
Monitoring Webhook alerts for workflow failures Detect issues within minutes instead of days

Scaling considerations:

For 10 verticals with 25 prospects each (250 total emails), expect the workflow to run for 20-30 minutes. If you're testing 30 verticals (750 emails), split the workflow into batches and run them on different schedules to avoid API timeouts.

Email deliverability:

Use a dedicated sending domain with proper SPF, DKIM, and DMARC records. Warm up your domain by sending to engaged contacts first. Monitor bounce rates and unsubscribe rates per vertical to identify deliverability issues early.

Real-World Use Cases

Use Case 1: SaaS Product Validation

  • Industry: B2B SaaS
  • Scale: Testing 15 verticals with 300 total prospects
  • Modifications needed: Add Stripe integration to track which verticals convert to paid trials
  • Result: Identified 3 high-converting verticals within 3 weeks

Use Case 2: Service Business Expansion

  • Industry: Professional services (consulting, coaching)
  • Scale: 20 verticals with 400 prospects
  • Modifications needed: Replace landing pages with Calendly booking links for each vertical
  • Result: Booked 45 discovery calls across 4 winning verticals

Use Case 3: E-commerce Product Launch

  • Industry: Direct-to-consumer products
  • Scale: 12 verticals with 360 prospects (B2B buyers)
  • Modifications needed: Add Shopify integration to track which verticals place wholesale orders
  • Result: Secured 8 wholesale accounts in 2 winning verticals

Customizing This Workflow

Alternative Integrations

Instead of Supabase:

  • Airtable: Best for non-technical users - requires swapping Supabase nodes for Airtable API nodes
  • PostgreSQL: Better for high-volume data - use n8n's Postgres node instead of Supabase
  • Google Sheets: Use when you need easy manual editing - replace Supabase with Google Sheets nodes

Instead of Exa.ai:

  • Apollo.io: Better B2B contact database - swap Exa.ai node for Apollo API calls
  • LinkedIn Sales Navigator: More accurate for enterprise prospects - requires manual export or scraping
  • Hunter.io: Simpler email finding - replace Exa.ai with Hunter domain search

Workflow Extensions

Add automated reporting:

  • Add a Schedule node to run weekly engagement analysis
  • Connect to Google Sheets API to generate comparison tables
  • Calculate engagement scores: (email opens × 1) + (clicks × 3) + (replies × 10)
  • Nodes needed: +4 (Schedule, Function, Google Sheets, Email)

Scale with A/B testing:

  • Generate 2-3 landing page variations per vertical
  • Split prospects into test groups
  • Track which copy performs best per vertical
  • Performance improvement: 30-50% higher conversion on winning variations

Integration possibilities:

Add This To Get This Complexity
Slack integration Real-time alerts when prospects reply Easy (2 nodes)
HubSpot CRM Automatic contact creation and deal tracking Medium (5 nodes)
Zapier webhook Connect to 1000+ other tools Easy (1 node)
Stripe payments Track which verticals convert to paid customers Medium (4 nodes)
Google Analytics Deep landing page behavior analysis Medium (3 nodes)

Customization ideas:

  • Add a sentiment analysis node to score email replies and prioritize high-intent responses
  • Integrate with a scheduling tool (Calendly, Cal.com) to book calls automatically from landing pages
  • Build a dashboard in Retool or Bubble that visualizes engagement metrics across all verticals
  • Add a follow-up sequence that sends 2-3 additional emails to non-responders
  • Connect to LinkedIn automation tools to send connection requests alongside emails

Get Started Today

Ready to automate your vertical prospecting?

  1. Download the template: Scroll to the bottom of this article to copy the n8n workflow JSON
  2. Import to n8n: Go to Workflows → Import from URL or File, paste the JSON
  3. Configure your services: Add API credentials for Claude, Supabase, Exa.ai, and your email service
  4. Test with sample data: Run the workflow with your product description and verify landing pages generate correctly
  5. Deploy to production: Set your schedule and activate the workflow to start testing verticals

Need help customizing this workflow for your specific product or want guidance on scaling your winning verticals? Schedule an intro call with Atherial.

Complete N8N Workflow Template

Copy the JSON below and import it into your N8N instance via Workflows → Import from File

{
  "name": "Multi-Vertical Product Validation Engine",
  "nodes": [
    {
      "id": "d1a8c2e4-b5f6-4c8d-9e1a-2b3c4d5e6f7a",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        250,
        300
      ],
      "parameters": {
        "path": "start-validation",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "onReceived"
      },
      "typeVersion": 2.1
    },
    {
      "id": "a2b3c4d5-e6f7-8a9b-0c1d-2e3f4a5b6c7d",
      "name": "AI - Identify Verticals",
      "type": "n8n-nodes-base.openAi",
      "position": [
        450,
        300
      ],
      "parameters": {
        "text": "={{ $json.productDescription }}\n\nAnalyze this product and identify 5 adjacent market verticals where it could solve problems. For each vertical, provide:\n1. Vertical name\n2. Industry description\n3. Key pain points (3-5 specific problems)\n4. Value proposition tailored to that vertical\n5. Target personas (job titles/roles)\n\nReturn as valid JSON array with this structure:\n[\n  {\n    \"vertical_name\": \"\",\n    \"industry\": \"\",\n    \"pain_points\": [],\n    \"value_proposition\": \"\",\n    \"target_personas\": []\n  }\n]",
        "model": "gpt-4",
        "options": {
          "temperature": 0.7
        },
        "resource": "text",
        "operation": "message"
      },
      "typeVersion": 1.1
    },
    {
      "id": "b3c4d5e6-f7a8-9b0c-1d2e-3f4a5b6c7d8e",
      "name": "Parse Verticals JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        650,
        300
      ],
      "parameters": {
        "jsCode": "const response = $input.first().json.message?.content || $input.first().json.choices?.[0]?.message?.content || '{}';\nlet verticals = [];\n\ntry {\n  verticals = JSON.parse(response);\n} catch (e) {\n  verticals = [];\n}\n\nreturn verticals.map((vertical, index) => ({\n  json: {\n    ...vertical,\n    product_id: $('Webhook Trigger').item.json.productId,\n    vertical_id: `vertical_${Date.now()}_${index}`,\n    created_at: new Date().toISOString(),\n    status: 'active'\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "c4d5e6f7-a8b9-0c1d-2e3f-4a5b6c7d8e9f",
      "name": "Supabase - Save Verticals",
      "type": "n8n-nodes-base.supabase",
      "position": [
        850,
        300
      ],
      "parameters": {
        "tableId": "verticals",
        "dataMode": "defineBelow",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "vertical_id",
              "fieldValue": "={{ $json.vertical_id }}"
            },
            {
              "fieldId": "product_id",
              "fieldValue": "={{ $json.product_id }}"
            },
            {
              "fieldId": "vertical_name",
              "fieldValue": "={{ $json.vertical_name }}"
            },
            {
              "fieldId": "industry",
              "fieldValue": "={{ $json.industry }}"
            },
            {
              "fieldId": "pain_points",
              "fieldValue": "={{ JSON.stringify($json.pain_points) }}"
            },
            {
              "fieldId": "value_proposition",
              "fieldValue": "={{ $json.value_proposition }}"
            },
            {
              "fieldId": "target_personas",
              "fieldValue": "={{ JSON.stringify($json.target_personas) }}"
            },
            {
              "fieldId": "status",
              "fieldValue": "={{ $json.status }}"
            },
            {
              "fieldId": "created_at",
              "fieldValue": "={{ $json.created_at }}"
            }
          ]
        },
        "resource": "row",
        "operation": "create"
      },
      "typeVersion": 1
    },
    {
      "id": "d5e6f7a8-b9c0-1d2e-3f4a-5b6c7d8e9f0a",
      "name": "Split Verticals",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1050,
        300
      ],
      "parameters": {
        "options": {},
        "batchSize": 1
      },
      "typeVersion": 3
    },
    {
      "id": "e6f7a8b9-c0d1-2e3f-4a5b-6c7d8e9f0a1b",
      "name": "AI - Generate Landing Page",
      "type": "n8n-nodes-base.openAi",
      "position": [
        1250,
        300
      ],
      "parameters": {
        "text": "=Generate a high-converting landing page for:\n\nProduct: {{ $('Webhook Trigger').item.json.productName }}\nVertical: {{ $json.vertical_name }}\nIndustry: {{ $json.industry }}\nPain Points: {{ JSON.stringify($json.pain_points) }}\nValue Prop: {{ $json.value_proposition }}\n\nCreate:\n1. Compelling headline (8-12 words)\n2. Subheadline (15-20 words)\n3. Hero section copy (50 words)\n4. 3 benefit sections with icons and descriptions\n5. Social proof placeholder text\n6. Strong CTA copy\n7. FAQ section (5 questions)\n\nReturn as JSON:\n{\n  \"headline\": \"\",\n  \"subheadline\": \"\",\n  \"hero_copy\": \"\",\n  \"benefits\": [{\"title\": \"\", \"description\": \"\", \"icon_suggestion\": \"\"}],\n  \"social_proof\": \"\",\n  \"cta_primary\": \"\",\n  \"cta_secondary\": \"\",\n  \"faqs\": [{\"question\": \"\", \"answer\": \"\"}]\n}",
        "model": "gpt-4",
        "options": {
          "temperature": 0.8
        },
        "resource": "text",
        "operation": "message"
      },
      "typeVersion": 1.1
    },
    {
      "id": "f7a8b9c0-d1e2-3f4a-5b6c-7d8e9f0a1b2c",
      "name": "Format Landing Page",
      "type": "n8n-nodes-base.code",
      "position": [
        1450,
        300
      ],
      "parameters": {
        "jsCode": "const responseData = $input.first().json;\nconst lpContent = JSON.parse(responseData.message?.content || responseData.choices?.[0]?.message?.content || '{}');\nconst verticalData = $('Split Verticals').item.json;\n\nreturn [{\n  json: {\n    vertical_id: verticalData.vertical_id,\n    landing_page_content: lpContent,\n    landing_page_url: `https://yoursite.com/lp/${verticalData.vertical_id}`,\n    created_at: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "a8b9c0d1-e2f3-4a5b-6c7d-8e9f0a1b2c3d",
      "name": "Supabase - Save Landing Page",
      "type": "n8n-nodes-base.supabase",
      "position": [
        1650,
        300
      ],
      "parameters": {
        "tableId": "landing_pages",
        "dataMode": "defineBelow",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "vertical_id",
              "fieldValue": "={{ $json.vertical_id }}"
            },
            {
              "fieldId": "content",
              "fieldValue": "={{ JSON.stringify($json.landing_page_content) }}"
            },
            {
              "fieldId": "url",
              "fieldValue": "={{ $json.landing_page_url }}"
            },
            {
              "fieldId": "created_at",
              "fieldValue": "={{ $json.created_at }}"
            }
          ]
        },
        "resource": "row",
        "operation": "create"
      },
      "typeVersion": 1
    },
    {
      "id": "b9c0d1e2-f3a4-5b6c-7d8e-9f0a1b2c3d4e",
      "name": "Exa.ai - Find Prospects",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1850,
        300
      ],
      "parameters": {
        "url": "https://api.exa.ai/search",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"query\": \"{{ $('Split Verticals').item.json.target_personas[0] }} at {{ $('Split Verticals').item.json.industry }} companies\",\n  \"num_results\": 50,\n  \"type\": \"company\",\n  \"include_domains\": [\"linkedin.com\"]\n}",
        "sendBody": true,
        "contentType": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.3
    },
    {
      "id": "c0d1e2f3-a4b5-6c7d-8e9f-0a1b2c3d4e5f",
      "name": "Parse Prospects",
      "type": "n8n-nodes-base.code",
      "position": [
        2050,
        300
      ],
      "parameters": {
        "jsCode": "const exaResults = $input.first().json.results || [];\nconst verticalData = $('Split Verticals').item.json;\n\nreturn exaResults.slice(0, 20).map(result => ({\n  json: {\n    vertical_id: verticalData.vertical_id,\n    prospect_name: result.title || 'Unknown',\n    prospect_company: result.domain || '',\n    prospect_url: result.url || '',\n    prospect_email: `contact@${result.domain}`,\n    status: 'new',\n    created_at: new Date().toISOString()\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "d1e2f3a4-b5c6-7d8e-9f0a-1b2c3d4e5f6a",
      "name": "Supabase - Save Prospects",
      "type": "n8n-nodes-base.supabase",
      "position": [
        2250,
        300
      ],
      "parameters": {
        "tableId": "prospects",
        "dataMode": "defineBelow",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "vertical_id",
              "fieldValue": "={{ $json.vertical_id }}"
            },
            {
              "fieldId": "name",
              "fieldValue": "={{ $json.prospect_name }}"
            },
            {
              "fieldId": "company",
              "fieldValue": "={{ $json.prospect_company }}"
            },
            {
              "fieldId": "url",
              "fieldValue": "={{ $json.prospect_url }}"
            },
            {
              "fieldId": "email",
              "fieldValue": "={{ $json.prospect_email }}"
            },
            {
              "fieldId": "status",
              "fieldValue": "={{ $json.status }}"
            },
            {
              "fieldId": "created_at",
              "fieldValue": "={{ $json.created_at }}"
            }
          ]
        },
        "resource": "row",
        "operation": "create"
      },
      "typeVersion": 1
    },
    {
      "id": "e2f3a4b5-c6d7-8e9f-0a1b-2c3d4e5f6a7b",
      "name": "AI - Generate Cold Email",
      "type": "n8n-nodes-base.openAi",
      "position": [
        2450,
        300
      ],
      "parameters": {
        "text": "=Write a personalized cold email for:\n\nProspect: {{ $json.prospect_name }}\nCompany: {{ $json.prospect_company }}\nVertical: {{ $('Split Verticals').item.json.vertical_name }}\nPain Points: {{ JSON.stringify($('Split Verticals').item.json.pain_points) }}\nValue Prop: {{ $('Split Verticals').item.json.value_proposition }}\nLanding Page: {{ $('Format Landing Page').item.json.landing_page_url }}\n\nWrite a concise, personalized cold email (max 150 words) that:\n1. Opens with a relevant observation about their industry\n2. Mentions 1-2 specific pain points\n3. Briefly explains how we solve it\n4. Includes a soft CTA to visit the landing page\n5. Keeps it conversational and non-salesy\n\nReturn as JSON:\n{\n  \"subject_line\": \"\",\n  \"email_body\": \"\"\n}",
        "model": "gpt-4",
        "options": {
          "temperature": 0.7
        },
        "resource": "text",
        "operation": "message"
      },
      "typeVersion": 1.1
    },
    {
      "id": "f3a4b5c6-d7e8-9f0a-1b2c-3d4e5f6a7b8c",
      "name": "SendGrid - Send Email",
      "type": "n8n-nodes-base.sendGrid",
      "position": [
        2650,
        300
      ],
      "parameters": {
        "message": "={{ JSON.parse($json.message?.content || $json.choices?.[0]?.message?.content || '{}').email_body }}",
        "subject": "={{ JSON.parse($json.message?.content || $json.choices?.[0]?.message?.content || '{}').subject_line }}",
        "toEmail": "={{ $('Supabase - Save Prospects').item.json.email }}",
        "bodyType": "text",
        "resource": "mail",
        "operation": "send",
        "additionalFields": {
          "fromName": "Your Company Team",
          "fromEmail": "outreach@yourcompany.com"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a4b5c6d7-e8f9-0a1b-2c3d-4e5f6a7b8c9d",
      "name": "Track Email Sent",
      "type": "n8n-nodes-base.code",
      "position": [
        2850,
        300
      ],
      "parameters": {
        "jsCode": "const emailResponse = $('AI - Generate Cold Email').item.json;\nconst emailContent = JSON.parse(emailResponse.message?.content || emailResponse.choices?.[0]?.message?.content || '{}');\nconst prospectData = $('Supabase - Save Prospects').item.json;\n\nreturn [{\n  json: {\n    prospect_email: prospectData.email,\n    vertical_id: prospectData.vertical_id,\n    email_subject: emailContent.subject_line,\n    email_body: emailContent.email_body,\n    sent_at: new Date().toISOString(),\n    status: 'sent',\n    opens: 0,\n    clicks: 0,\n    replies: 0\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "b5c6d7e8-f9a0-1b2c-3d4e-5f6a7b8c9d0e",
      "name": "Supabase - Save Campaign",
      "type": "n8n-nodes-base.supabase",
      "position": [
        3050,
        300
      ],
      "parameters": {
        "tableId": "email_campaigns",
        "dataMode": "defineBelow",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "prospect_email",
              "fieldValue": "={{ $json.prospect_email }}"
            },
            {
              "fieldId": "vertical_id",
              "fieldValue": "={{ $json.vertical_id }}"
            },
            {
              "fieldId": "subject",
              "fieldValue": "={{ $json.email_subject }}"
            },
            {
              "fieldId": "body",
              "fieldValue": "={{ $json.email_body }}"
            },
            {
              "fieldId": "sent_at",
              "fieldValue": "={{ $json.sent_at }}"
            },
            {
              "fieldId": "status",
              "fieldValue": "={{ $json.status }}"
            },
            {
              "fieldId": "opens",
              "fieldValue": "={{ $json.opens }}"
            },
            {
              "fieldId": "clicks",
              "fieldValue": "={{ $json.clicks }}"
            },
            {
              "fieldId": "replies",
              "fieldValue": "={{ $json.replies }}"
            }
          ]
        },
        "resource": "row",
        "operation": "create"
      },
      "typeVersion": 1
    },
    {
      "id": "c6d7e8f9-a0b1-2c3d-4e5f-6a7b8c9d0e1f",
      "name": "Webhook - Email Tracking",
      "type": "n8n-nodes-base.webhook",
      "position": [
        250,
        600
      ],
      "parameters": {
        "path": "email-tracking",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "onReceived"
      },
      "typeVersion": 2.1
    },
    {
      "id": "d7e8f9a0-b1c2-3d4e-5f6a-7b8c9d0e1f2a",
      "name": "Supabase - Update Tracking",
      "type": "n8n-nodes-base.supabase",
      "position": [
        450,
        600
      ],
      "parameters": {
        "tableId": "email_campaigns",
        "dataMode": "defineBelow",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "opens",
              "fieldValue": "={{ $json.event === 'open' ? 1 : 0 }}"
            },
            {
              "fieldId": "clicks",
              "fieldValue": "={{ $json.event === 'click' ? 1 : 0 }}"
            },
            {
              "fieldId": "replies",
              "fieldValue": "={{ $json.event === 'reply' ? 1 : 0 }}"
            },
            {
              "fieldId": "updated_at",
              "fieldValue": "={{ $now.toISO() }}"
            }
          ]
        },
        "resource": "row",
        "operation": "update",
        "whereClause": "=id={{ $json.campaign_id }}"
      },
      "typeVersion": 1
    },
    {
      "id": "e8f9a0b1-c2d3-4e5f-6a7b-8c9d0e1f2a3b",
      "name": "Webhook - Analytics Dashboard",
      "type": "n8n-nodes-base.webhook",
      "position": [
        250,
        900
      ],
      "parameters": {
        "path": "analytics-dashboard",
        "options": {},
        "httpMethod": "GET",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "f9a0b1c2-d3e4-5f6a-7b8c-9d0e1f2a3b4c",
      "name": "Supabase - Get Verticals",
      "type": "n8n-nodes-base.supabase",
      "position": [
        450,
        900
      ],
      "parameters": {
        "tableId": "verticals",
        "resource": "row",
        "operation": "getAll",
        "returnAll": true
      },
      "typeVersion": 1
    },
    {
      "id": "a0b1c2d3-e4f5-6a7b-8c9d-0e1f2a3b4c5d",
      "name": "Supabase - Get Campaigns",
      "type": "n8n-nodes-base.supabase",
      "position": [
        650,
        900
      ],
      "parameters": {
        "tableId": "email_campaigns",
        "resource": "row",
        "operation": "getAll",
        "returnAll": true
      },
      "typeVersion": 1
    },
    {
      "id": "b1c2d3e4-f5a6-7b8c-9d0e-1f2a3b4c5d6e",
      "name": "Generate Analytics Dashboard",
      "type": "n8n-nodes-base.code",
      "position": [
        850,
        900
      ],
      "parameters": {
        "jsCode": "const verticalsData = $('Supabase - Get Verticals').all();\nconst campaignsData = $('Supabase - Get Campaigns').all();\n\nconst analytics = verticalsData.map(verticalItem => {\n  const vertical = verticalItem.json;\n  const verticalCampaigns = campaignsData.filter(c => c.json.vertical_id === vertical.vertical_id);\n  \n  const totalSent = verticalCampaigns.length;\n  const totalOpens = verticalCampaigns.reduce((sum, c) => sum + (c.json.opens || 0), 0);\n  const totalClicks = verticalCampaigns.reduce((sum, c) => sum + (c.json.clicks || 0), 0);\n  const totalReplies = verticalCampaigns.reduce((sum, c) => sum + (c.json.replies || 0), 0);\n  \n  return {\n    vertical_name: vertical.vertical_name,\n    industry: vertical.industry,\n    emails_sent: totalSent,\n    open_rate: totalSent > 0 ? ((totalOpens / totalSent) * 100).toFixed(2) + '%' : '0%',\n    click_rate: totalSent > 0 ? ((totalClicks / totalSent) * 100).toFixed(2) + '%' : '0%',\n    reply_rate: totalSent > 0 ? ((totalReplies / totalSent) * 100).toFixed(2) + '%' : '0%',\n    conversion_score: totalOpens + (totalClicks * 2) + (totalReplies * 5)\n  };\n});\n\nanalytics.sort((a, b) => b.conversion_score - a.conversion_score);\n\nreturn [{\n  json: {\n    summary: {\n      total_verticals: verticalsData.length,\n      total_campaigns: campaignsData.length,\n      best_performing_vertical: analytics[0]?.vertical_name || 'N/A'\n    },\n    verticals: analytics,\n    generated_at: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Parse Prospects": {
      "main": [
        [
          {
            "node": "Supabase - Save Prospects",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Verticals": {
      "main": [
        [
          {
            "node": "AI - Generate Landing Page",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "AI - Identify Verticals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Track Email Sent": {
      "main": [
        [
          {
            "node": "Supabase - Save Campaign",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Landing Page": {
      "main": [
        [
          {
            "node": "Supabase - Save Landing Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Verticals JSON": {
      "main": [
        [
          {
            "node": "Supabase - Save Verticals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SendGrid - Send Email": {
      "main": [
        [
          {
            "node": "Track Email Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI - Identify Verticals": {
      "main": [
        [
          {
            "node": "Parse Verticals JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Exa.ai - Find Prospects": {
      "main": [
        [
          {
            "node": "Parse Prospects",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI - Generate Cold Email": {
      "main": [
        [
          {
            "node": "SendGrid - Send Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase - Get Campaigns": {
      "main": [
        [
          {
            "node": "Generate Analytics Dashboard",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase - Get Verticals": {
      "main": [
        [
          {
            "node": "Supabase - Get Campaigns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase - Save Campaign": {
      "main": [
        [
          {
            "node": "Split Verticals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - Email Tracking": {
      "main": [
        [
          {
            "node": "Supabase - Update Tracking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase - Save Prospects": {
      "main": [
        [
          {
            "node": "AI - Generate Cold Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase - Save Verticals": {
      "main": [
        [
          {
            "node": "Split Verticals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI - Generate Landing Page": {
      "main": [
        [
          {
            "node": "Format Landing Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase - Save Landing Page": {
      "main": [
        [
          {
            "node": "Exa.ai - Find Prospects",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - Analytics Dashboard": {
      "main": [
        [
          {
            "node": "Supabase - Get Verticals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}