This workflow follows the HTTP Request → OpenAI recipe pattern — see all workflows that pair these two integrations.
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": "Phase 3 - First Message",
"nodes": [
{
"parameters": {
"modelId": {
"__rl": true,
"value": "gpt-4o-mini",
"mode": "list",
"cachedResultName": "GPT-4O-MINI"
},
"responses": {
"values": [
{
"role": "system",
"content": "You write the FIRST LinkedIn outreach message from a partnerships lead at Learn with Leaders (LwL). LwL partners with K-12 schools worldwide to bring student leadership and enrichment programs: World Leaders Academy, Edge Club, Future Doctors Fellowship, and TEO Launchpad. Write ONE short LinkedIn DM (about 40-60 words, 2-4 sentences). Tone: warm, professional, human, specific to this person and school. Reference their role and school naturally. Goal: open a short conversation. Make ONE clear, low-friction ask (e.g., whether they are open to a quick chat). Do NOT hard-sell, do NOT paste any link, do NOT invent facts about the school. No 'Dear', no subject line, no sign-off block - just the message. Return ONLY the message text."
},
{
"content": "={{ $json.userPrompt }}"
}
]
},
"builtInTools": {},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 2.3,
"position": [
1408,
944
],
"id": "836990d9-c146-4596-8d75-6f01897912e0",
"name": "Message a model",
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const out = [];\nfor (const item of items) {\n const c = item.json;\n const s = Array.isArray(c.schools) ? (c.schools[0] || {}) : (c.schools || {});\n const userPrompt =\n \"Write the first outreach message for:\\n\" +\n \"- Contact name: \" + (c.name || 'there') + \"\\n\" +\n \"- Role: \" + (c.role || 'school leader') + \"\\n\" +\n \"- School: \" + (s.name || 'their school') + \"\\n\" +\n \"- City: \" + (s.city || 'n/a') + \"\\n\" +\n \"- Curriculum/board: \" + (s.board || 'n/a') + \"\\n\" +\n \"(Internal only, do NOT mention: tier \" + (s.tier != null ? s.tier : 'n/a') + \".)\";\n out.push({ json: { contactId: c.id, name: c.name, schoolName: s.name || null, userPrompt: userPrompt } });\n}\nreturn out;\n"
},
"id": "eb1a3124-db93-40b5-9403-ca7ca93fe2ba",
"name": "Prep Fields",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1200,
944
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/messages' }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "supabaseApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Prefer",
"value": "return=minimal"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { \"contact_id\": $json.contactId, \"direction\": \"outbound\", \"body\": $json.messageBody, \"source\": \"ai\" } }}",
"options": {}
},
"id": "a72ec124-b891-4923-934b-d45d6c87d9c2",
"name": "Insert Message",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2160,
816
],
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 2000,
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "d994ae54-58aa-449a-b9dc-89a1ada89d61",
"name": "supabaseUrl",
"value": "https://YOUR_PROJECT_REF.supabase.co",
"type": "string"
}
]
},
"options": {}
},
"id": "d040ecba-119f-466a-9b62-1d8713f2f3e4",
"name": "Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
768,
944
]
},
{
"parameters": {
"method": "PATCH",
"url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/contacts?id=eq.' + $json.contactId }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "supabaseApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Prefer",
"value": "return=minimal"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { \"outreach_status\": \"message_sent\", \"last_contacted_at\": $now.toISO() } }}",
"options": {}
},
"id": "dcead2f0-c16f-4337-af26-9606eecff666",
"name": "Update Contact Status",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2176,
1040
],
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 2000,
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/contacts?outreach_status=eq.not_contacted&select=id,name,role,school_id,schools(name,tier,board,city,tier_reason)&limit=5' }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "supabaseApi",
"options": {}
},
"id": "7851e952-c6f6-4e58-ba17-7d362ede69dc",
"name": "Get Not-Contacted",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
976,
944
],
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 2000,
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const prep = $('Prep Fields').all();\n\nfunction extractText(r) {\n if (r == null) return '';\n if (typeof r === 'string') return r;\n // OpenAI Responses API: output: [ { content: [ { type:'output_text', text } ] } ]\n if (Array.isArray(r.output)) {\n let acc = '';\n for (const msg of r.output) {\n if (msg && Array.isArray(msg.content)) {\n for (const c of msg.content) { if (c && typeof c.text === 'string') acc += c.text; }\n } else if (typeof msg === 'string') { acc += msg; }\n else if (msg && typeof msg.text === 'string') { acc += msg.text; }\n }\n if (acc) return acc;\n }\n if (typeof r.output_text === 'string') return r.output_text;\n if (typeof r.output === 'string') return r.output;\n if (typeof r.content === 'string') return r.content;\n if (typeof r.text === 'string') return r.text;\n if (r.message && typeof r.message.content === 'string') return r.message.content;\n if (r.choices && r.choices[0] && r.choices[0].message && typeof r.choices[0].message.content === 'string') return r.choices[0].message.content;\n if (Array.isArray(r.content)) return r.content.map(b => (b && b.text) ? b.text : '').join('');\n return '';\n}\n\nconst out = [];\nfor (let i = 0; i < items.length; i++) {\n const text = extractText(items[i].json).trim();\n const c = (prep[i] && prep[i].json) ? prep[i].json : {};\n out.push({ json: { contactId: c.contactId, name: c.name, messageBody: text } });\n}\nreturn out;"
},
"id": "fea5d5e3-d52d-4717-a0f3-3f561310841d",
"name": "Extract Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1776,
944
]
},
{
"parameters": {},
"id": "4f1e7da5-cf7b-4d64-bbd6-3b9f4a2f99e8",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
548,
944
]
}
],
"connections": {
"Get Not-Contacted": {
"main": [
[
{
"node": "Prep Fields",
"type": "main",
"index": 0
}
]
]
},
"Prep Fields": {
"main": [
[
{
"node": "Message a model",
"type": "main",
"index": 0
}
]
]
},
"Extract Message": {
"main": [
[
{
"node": "Insert Message",
"type": "main",
"index": 0
},
{
"node": "Update Contact Status",
"type": "main",
"index": 0
}
]
]
},
"Config": {
"main": [
[
{
"node": "Get Not-Contacted",
"type": "main",
"index": 0
}
]
]
},
"Message a model": {
"main": [
[
{
"node": "Extract Message",
"type": "main",
"index": 0
}
]
]
},
"Manual Trigger": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApisupabaseApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Phase 3 - First Message. Uses openAi, httpRequest. Event-driven trigger; 8 nodes.
Source: https://github.com/Tusharvijaypatil/LWL-Growth-Engine/blob/main/Workflows/phase2_first_message.json — 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.
Ask questions like “How much did I spend on food last month?” and get instant answers from your financial data — directly in Telegram.
Analyze incoming support requests, classify intent and priority with AI, create Jira tickets, assign the correct team, send Slack notifications, and track SLA deadlines. Supports Gmail, WhatsApp, form
The Problem That it Solves
This intelligent email automation workflow helps you maximize engagement through domain-based outreach. It utilizes AI-powered personalization and strategic follow-ups to increase response rates. The
Note: Now includes an Apify alternative for Rapid API (Some users can't create new accounts on Rapid API, so I have added an alternative for you. But immediately you are able to get access to Rapid AP