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 →
{
"name": "LinkedIn Outreach: PhantomBuster + OpenAI + Human Review (Compat)",
"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",
"method": "POST",
"jsonParameters": true,
"headerParametersJson": "{\"X-Phantombuster-Key-1\":\"O1jLrrHNXybkStIYIkX09htdCY9bYlfUsHrniF58uLw\",\"Content-Type\":\"application/json\"}",
"bodyParametersJson": "={\"id\":\"SCRAPER_AGENT_ID\",\"argument\":{\"profileUrls\":[\"{{$json.profileUrl}}\"],\"spreadsheetUrl\":null}}"
},
"id": "PB_LaunchScraper",
"name": "PhantomBuster: Launch Scraper",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"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",
"method": "GET",
"headerParametersJson": "{\"X-Phantombuster-Key-1\":\"O1jLrrHNXybkStIYIkX09htdCY9bYlfUsHrniF58uLw\"}"
},
"id": "PB_FetchOutput",
"name": "PhantomBuster: Fetch Output",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"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",
"method": "POST",
"jsonParameters": true,
"headerParametersJson": "{\"Authorization\":\"Bearer OPENAI_API_KEY\",\"Content-Type\":\"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": 3,
"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"
},
"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",
"method": "POST",
"jsonParameters": true,
"headerParametersJson": "{\"X-Phantombuster-Key-1\":\"O1jLrrHNXybkStIYIkX09htdCY9bYlfUsHrniF58uLw\",\"Content-Type\":\"application/json\"}",
"bodyParametersJson": "={\"id\":\"SENDER_AGENT_ID\",\"argument\":{\"leads\":[{\"profileUrl\":\"{{$json.profileUrl}}\",\"message\":\"{{$json.draft}}\"}]}}"
},
"id": "PB_SendMessage",
"name": "PhantomBuster: Launch Message Sender",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"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
}
]
]
}
}
}
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 Review (Compat). Uses httpRequest. Event-driven trigger; 18 nodes.
Source: https://gist.github.com/slvsazonov/a3285f9c573f19e2cb4390deb2e89a54 — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
legal_rag_telegram_api_current_github_ready. Uses telegramTrigger, httpRequest. Event-driven trigger; 56 nodes.
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
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
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
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