AutomationFlowsAI & RAG › Linkedin Outreach: Phantombuster + Openai + Human Approval (with Pb Key)

Linkedin Outreach: Phantombuster + Openai + Human Approval (with Pb Key)

LinkedIn Outreach: PhantomBuster + OpenAI + Human Approval (with PB key). Uses httpRequest. Event-driven trigger; 18 nodes.

Event trigger★★★★☆ complexity18 nodesHTTP Request
AI & RAG Trigger: Event Nodes: 18 Complexity: ★★★★☆ Added:

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "LinkedIn Outreach: PhantomBuster + OpenAI + Human Approval (with PB key)",
  "nodes": [
    {
      "parameters": {},
      "id": "ManualTrigger",
      "name": "Start (Manual)",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        200,
        200
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [],
          "json": [
            {
              "name": "contacts",
              "value": [
                {
                  "profileUrl": "https://www.linkedin.com/in/REPLACE_CONTACT_1/"
                },
                {
                  "profileUrl": "https://www.linkedin.com/in/REPLACE_CONTACT_2/"
                }
              ]
            }
          ]
        }
      },
      "id": "ContactsSet",
      "name": "Contacts (Set)",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [
        400,
        200
      ]
    },
    {
      "parameters": {
        "batchSize": 1
      },
      "id": "SplitBatches",
      "name": "Split in Batches",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 2,
      "position": [
        600,
        200
      ]
    },
    {
      "parameters": {
        "functionCode": "const list = items[0].json.contacts || [];\nconst i = $runOnce().get('idx') ?? 0;\n$runOnce().set('idx', i + 1);\nif (!list[i]) { return []; }\nreturn [{ json: { contactId: i+1, profileUrl: list[i].profileUrl } }];"
      },
      "id": "CurrentContact",
      "name": "Current Contact",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        800,
        200
      ]
    },
    {
      "parameters": {
        "url": "https://api.phantombuster.com/api/v2/agents/launch",
        "options": {},
        "jsonParameters": true,
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Phantombuster-Key-1",
              "value": "O1jLrrHNXybkStIYIkX09htdCY9bYlfUsHrniF58uLw"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "bodyParametersJson": "={\"id\":\"SCRAPER_AGENT_ID\",\"argument\":{\"profileUrls\":[\"{{$json.profileUrl}}\"],\"spreadsheetUrl\":null}}",
        "method": "POST"
      },
      "id": "PB_LaunchScraper",
      "name": "PhantomBuster: Launch Scraper",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1000,
        200
      ]
    },
    {
      "parameters": {
        "amount": 25,
        "unit": "seconds"
      },
      "id": "Wait_Scrape",
      "name": "Wait (Scrape)",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 2,
      "position": [
        1200,
        200
      ]
    },
    {
      "parameters": {
        "url": "https://api.phantombuster.com/api/v2/agents/fetch-output?id=SCRAPER_AGENT_ID",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Phantombuster-Key-1",
              "value": "O1jLrrHNXybkStIYIkX09htdCY9bYlfUsHrniF58uLw"
            }
          ]
        },
        "method": "GET"
      },
      "id": "PB_FetchOutput",
      "name": "PhantomBuster: Fetch Output",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1400,
        200
      ]
    },
    {
      "parameters": {
        "functionCode": "const out = items[0].json || {};\nconst row = (out.resultObject && out.resultObject.data && out.resultObject.data[0]) || (out.data && out.data[0]) || {};\nreturn [{ json: {\n  contactId: $json.contactId || 0,\n  profileUrl: $json.profileUrl || '',\n  fullName: row.fullName || row.name || '',\n  headline: row.headline || row.jobTitle || '',\n  company: row.company || row.currentCompany || '',\n  summary: row.summary || row.about || '',\n  skills: row.skills || [],\n  experience: row.experiences || row.experience || []\n}}];"
      },
      "id": "ExtractProfile",
      "name": "Extract Profile Data",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        1600,
        200
      ]
    },
    {
      "parameters": {
        "keepOnlySet": false,
        "values": {
          "string": [
            {
              "name": "template",
              "value": "Hi {{fullName}}, loved your work at {{company}} as {{headline}}. I\u2019m reaching out because {{reason}}. Based on your background in {{skillList}}, I think this could be valuable. Would you be open to a quick chat?"
            },
            {
              "name": "reason",
              "value": "we help {{company}}-type teams automate outreach without losing personalization"
            }
          ]
        }
      },
      "id": "MessageTemplate",
      "name": "Message Template (Set)",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [
        1800,
        200
      ]
    },
    {
      "parameters": {
        "functionCode": "const skills = Array.isArray($json.skills) ? $json.skills.slice(0,6).join(', ') : String($json.skills||'');\nconst t = $json.template || '';\nconst filled = t\n  .replaceAll('{{fullName}}', $json.fullName || 'there')\n  .replaceAll('{{company}}', $json.company || 'your company')\n  .replaceAll('{{headline}}', $json.headline || 'your role')\n  .replaceAll('{{skillList}}', skills)\n  .replaceAll('{{reason}}', $json.reason || 'we might collaborate');\nconst system = 'You craft concise, friendly LinkedIn outreach. 280 characters max. Keep it professional and specific.';\nconst user = `PROFILE:\\nName: ${$json.fullName}\\nHeadline: ${$json.headline}\\nCompany: ${$json.company}\\nSummary: ${(String($json.summary||'')).slice(0,500)}\\nTop skills: ${skills}\\n\\nTEMPLATE (adapt under 280 chars):\\n${filled}`;\nreturn [{ json: { contactId: $json.contactId, profileUrl: $json.profileUrl, fullName: $json.fullName, prompt: { system, user }, seedTemplate: t, filledTemplate: filled } }];"
      },
      "id": "BuildPrompt",
      "name": "Build Prompt",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        2000,
        200
      ]
    },
    {
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "options": {},
        "jsonParameters": true,
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer OPENAI_API_KEY"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "bodyParametersJson": "={\n  \"model\": \"gpt-4o-mini\",\n  \"messages\": [\n    {\"role\": \"system\", \"content\": $json.prompt.system },\n    {\"role\": \"user\", \"content\": $json.prompt.user }\n  ],\n  \"temperature\": 0.7\n}"
      },
      "id": "OpenAIChat",
      "name": "OpenAI: Chat",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        2200,
        200
      ]
    },
    {
      "parameters": {
        "functionCode": "const c = items[0].json || {};\nconst msg = (c.choices && c.choices[0] && c.choices[0].message && c.choices[0].message.content) || '';\nreturn [{ json: { contactId: $json.contactId, profileUrl: $json.profileUrl, fullName: $json.fullName, draft: msg } }];"
      },
      "id": "CollectDraft",
      "name": "Collect Draft",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        2400,
        200
      ]
    },
    {
      "parameters": {
        "path": "linkedin-approve",
        "responseMode": "lastNode",
        "options": {}
      },
      "id": "WebhookApproval",
      "name": "Webhook (Approve/Reject)",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        2600,
        200
      ]
    },
    {
      "parameters": {
        "functionCode": "const qs = $json.query || {};\nconst approved = String(qs.approve || '').toLowerCase() === 'true';\nreturn [{ json: { approved, contactId: $json.contactId, profileUrl: $json.profileUrl, draft: $json.draft } }];"
      },
      "id": "ParseApproval",
      "name": "Parse Approval",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        2800,
        200
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json.approved}}",
              "operation": "isTrue"
            }
          ]
        }
      },
      "id": "IfApproved",
      "name": "IF Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        3000,
        200
      ]
    },
    {
      "parameters": {
        "url": "https://api.phantombuster.com/api/v2/agents/launch",
        "options": {},
        "jsonParameters": true,
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Phantombuster-Key-1",
              "value": "O1jLrrHNXybkStIYIkX09htdCY9bYlfUsHrniF58uLw"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "bodyParametersJson": "={\"id\":\"SENDER_AGENT_ID\",\"argument\":{\"leads\":[{\"profileUrl\":\"{{$json.profileUrl}}\",\"message\":\"{{$json.draft}}\"}]}}",
        "method": "POST"
      },
      "id": "PB_SendMessage",
      "name": "PhantomBuster: Launch Message Sender",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        3200,
        130
      ]
    },
    {
      "parameters": {},
      "id": "Rejected",
      "name": "Rejected (Log)",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        3200,
        270
      ]
    },
    {
      "parameters": {},
      "id": "Done",
      "name": "Done",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        3400,
        200
      ]
    }
  ],
  "connections": {
    "Start (Manual)": {
      "main": [
        [
          {
            "node": "Contacts (Set)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Contacts (Set)": {
      "main": [
        [
          {
            "node": "Split in Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split in Batches": {
      "main": [
        [
          {
            "node": "Current Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Current Contact": {
      "main": [
        [
          {
            "node": "PhantomBuster: Launch Scraper",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PhantomBuster: Launch Scraper": {
      "main": [
        [
          {
            "node": "Wait (Scrape)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait (Scrape)": {
      "main": [
        [
          {
            "node": "PhantomBuster: Fetch Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PhantomBuster: Fetch Output": {
      "main": [
        [
          {
            "node": "Extract Profile Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Profile Data": {
      "main": [
        [
          {
            "node": "Message Template (Set)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Message Template (Set)": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Prompt": {
      "main": [
        [
          {
            "node": "OpenAI: Chat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI: Chat": {
      "main": [
        [
          {
            "node": "Collect Draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect Draft": {
      "main": [
        [
          {
            "node": "Webhook (Approve/Reject)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook (Approve/Reject)": {
      "main": [
        [
          {
            "node": "Parse Approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Approval": {
      "main": [
        [
          {
            "node": "IF Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF Approved?": {
      "main": [
        [
          {
            "node": "PhantomBuster: Launch Message Sender",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Rejected (Log)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PhantomBuster: Launch Message Sender": {
      "main": [
        [
          {
            "node": "Done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rejected (Log)": {
      "main": [
        [
          {
            "node": "Done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

LinkedIn Outreach: PhantomBuster + OpenAI + Human Approval (with PB key). Uses httpRequest. Event-driven trigger; 18 nodes.

Source: https://gist.github.com/slvsazonov/ad9e3309c2de462ebd2d1bef9882cff0 — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

legal_rag_telegram_api_current_github_ready. Uses telegramTrigger, httpRequest. Event-driven trigger; 56 nodes.

Telegram Trigger, HTTP Request
AI & RAG

This n8n workflow automatically generates presentation-style "screen recording" videos with AI-generated slides and a talking head avatar overlay. You provide a topic and intention, and the workflow h

HTTP Request, N8N Nodes Veed, Google Drive +1
AI & RAG

Monitor Google Drive folder, parsing PDF, DOCX and image file into a destination folder, ready for further processing (e.g. RAG ingestion, translation, etc.) Keep processing log in Google Sheet and se

Google Drive Trigger, Google Drive, HTTP Request +2
AI & RAG

This workflow is designed for individuals and businesses looking to streamline the creation of engaging promotional videos. Whether you're marketing a product or developing a personal brand, this AI-d

HTTP Request, Google Cloud Storage, Google Sheets
AI & RAG

Transform trending Google News articles into engaging YouTube Shorts with this fully automated workflow. Save time and effort while creating dynamic, eye-catching videos that are perfect for content c

HTTP Request, Google Cloud Storage, Google Sheets +1