This workflow follows the HTTP Request → Notion 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": "14 - AI Meeting Notes \u2192 Action Items \u2192 Notion",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "meeting-notes",
"responseMode": "responseNode",
"options": {
"binaryData": true
}
},
"id": "node-webhook",
"name": "Webhook - Audio/Notes Upload",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
260,
300
]
},
{
"parameters": {
"jsCode": "const item = $input.first();\nconst body = item.json.body || item.json;\n\n// Check if this is audio upload (binary) or text transcript\nconst hasBinary = item.binary && Object.keys(item.binary).length > 0;\nconst hasTextTranscript = body.transcript || body.text;\n\nreturn [{\n json: {\n meetingTitle: body.title || body.meetingTitle || 'Meeting Notes',\n meetingDate: body.date || new Date().toISOString().split('T')[0],\n attendees: body.attendees || body.participants || '',\n project: body.project || '',\n submittedBy: body.submittedBy || body.email || '',\n inputType: hasBinary ? 'audio' : 'text',\n textTranscript: hasTextTranscript ? (body.transcript || body.text) : null\n },\n binary: item.binary || {}\n}];"
},
"id": "node-parse-input",
"name": "Code - Parse Input Type",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
300
]
},
{
"parameters": {
"conditions": {
"conditions": [
{
"leftValue": "={{ $json.inputType }}",
"rightValue": "audio",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
}
},
"id": "node-if-audio",
"name": "IF - Audio Input?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
700,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.openai.com/v1/audio/transcriptions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env['OPENAI_API_KEY'] }}"
}
]
},
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"name": "model",
"value": "whisper-1"
},
{
"name": "language",
"value": "en"
},
{
"name": "response_format",
"value": "verbose_json"
},
{
"name": "timestamp_granularities[]",
"value": "segment"
}
]
},
"options": {
"bodyContentType": "multipart-form-data"
}
},
"id": "node-whisper",
"name": "HTTP - Whisper Transcription",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
920,
180
]
},
{
"parameters": {
"jsCode": "const parsed = $('Code - Parse Input Type').first().json;\nconst whisperResult = $input.first().json;\n\nconst transcript = whisperResult.text || parsed.textTranscript || 'No transcript available';\nconst duration = whisperResult.duration ? `${Math.round(whisperResult.duration / 60)} minutes` : 'Unknown';\n\nreturn [{\n json: {\n ...parsed,\n transcript,\n duration\n }\n}];"
},
"id": "node-merge-transcript",
"name": "Code - Merge Transcript",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1140,
300
]
},
{
"parameters": {
"resource": "text",
"operation": "message",
"modelId": {
"__rl": true,
"value": "gpt-4o",
"mode": "list"
},
"messages": {
"values": [
{
"role": "system",
"content": "You are an expert meeting facilitator and note-taker. Analyze the meeting transcript and produce structured output.\n\nReturn a JSON object with:\n{\n \"summary\": \"2-3 paragraph executive summary of the meeting\",\n \"key_decisions\": [\"Decision 1\", \"Decision 2\"],\n \"action_items\": [\n {\n \"task\": \"Clear task description\",\n \"owner\": \"Person's name (or 'TBD')\",\n \"due_date\": \"YYYY-MM-DD or 'No date set'\",\n \"priority\": \"High|Medium|Low\"\n }\n ],\n \"blockers\": [\"Blocker 1\"],\n \"topics_discussed\": [\"Topic 1\", \"Topic 2\"],\n \"next_meeting\": \"Date/time if mentioned, or 'Not scheduled'\"\n}\n\nBe specific and actionable. Extract real names from the transcript for task owners."
},
{
"role": "user",
"content": "Meeting: {{ $json.meetingTitle }}\nDate: {{ $json.meetingDate }}\nAttendees: {{ $json.attendees }}\nProject: {{ $json.project }}\nDuration: {{ $json.duration }}\n\nTranscript:\n{{ $json.transcript }}"
}
]
},
"options": {
"temperature": 0.3,
"maxTokens": 2000
}
},
"id": "node-gpt-analyze",
"name": "GPT-4o - Analyze Meeting",
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 1.7,
"position": [
1360,
300
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const meetingData = $('Code - Merge Transcript').first().json;\nconst aiRaw = $input.first().json.message?.content || '{}';\n\nlet analysis;\ntry { analysis = JSON.parse(aiRaw); }\ncatch (e) { analysis = { summary: aiRaw, key_decisions: [], action_items: [], blockers: [], topics_discussed: [], next_meeting: 'Not scheduled' }; }\n\n// Build Notion page blocks\nconst actionItemsBlocks = (analysis.action_items || []).map(item =>\n `\u2610 **${item.task}** \u2014 Owner: ${item.owner} | Due: ${item.due_date} | Priority: ${item.priority}`\n).join('\\n');\n\nconst decisionsText = (analysis.key_decisions || []).map(d => `\u2022 ${d}`).join('\\n');\nconst blockersText = (analysis.blockers || []).map(b => `\u26a0\ufe0f ${b}`).join('\\n');\nconst topicsText = (analysis.topics_discussed || []).map(t => `\u2022 ${t}`).join('\\n');\n\nreturn [{\n json: {\n ...meetingData,\n analysis,\n actionItemsBlocks,\n decisionsText,\n blockersText,\n topicsText,\n pageTitle: `${meetingData.meetingDate} \u2014 ${meetingData.meetingTitle}`\n }\n}];"
},
"id": "node-parse-analysis",
"name": "Code - Parse & Format Analysis",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1580,
300
]
},
{
"parameters": {
"resource": "page",
"operation": "create",
"databaseId": {
"__rl": true,
"value": "YOUR_NOTION_MEETINGS_DB",
"mode": "id"
},
"title": "={{ $json.pageTitle }}",
"propertiesUi": {
"propertyValues": [
{
"key": "Date",
"type": "date",
"date": "={{ $json.meetingDate }}"
},
{
"key": "Project",
"type": "rich_text",
"textContent": "={{ $json.project }}"
},
{
"key": "Attendees",
"type": "rich_text",
"textContent": "={{ $json.attendees }}"
},
{
"key": "Duration",
"type": "rich_text",
"textContent": "={{ $json.duration }}"
},
{
"key": "Action Items Count",
"type": "number",
"numberValue": "={{ ($json.analysis.action_items || []).length }}"
},
{
"key": "Next Meeting",
"type": "rich_text",
"textContent": "={{ $json.analysis.next_meeting }}"
}
]
},
"blockUi": {
"blockValues": [
{
"type": "heading_2",
"textContent": "\ud83d\udccb Summary"
},
{
"type": "paragraph",
"textContent": "={{ $json.analysis.summary }}"
},
{
"type": "divider"
},
{
"type": "heading_2",
"textContent": "\u2705 Action Items"
},
{
"type": "paragraph",
"textContent": "={{ $json.actionItemsBlocks }}"
},
{
"type": "divider"
},
{
"type": "heading_2",
"textContent": "\ud83c\udfaf Key Decisions"
},
{
"type": "paragraph",
"textContent": "={{ $json.decisionsText }}"
},
{
"type": "heading_2",
"textContent": "\ud83d\udd35 Topics Discussed"
},
{
"type": "paragraph",
"textContent": "={{ $json.topicsText }}"
},
{
"type": "heading_2",
"textContent": "\u26a0\ufe0f Blockers & Risks"
},
{
"type": "paragraph",
"textContent": "={{ $json.blockersText || 'None identified' }}"
},
{
"type": "divider"
},
{
"type": "heading_2",
"textContent": "\ud83d\udcdd Full Transcript"
},
{
"type": "paragraph",
"textContent": "={{ $json.transcript }}"
}
]
}
},
"id": "node-notion-create",
"name": "Notion - Create Meeting Page",
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
1800,
300
],
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": true,\n \"notionUrl\": \"{{ $json.url }}\",\n \"actionItems\": {{ $('Code - Parse & Format Analysis').item.json.analysis.action_items?.length || 0 }},\n \"message\": \"Meeting notes processed and saved to Notion\"\n}"
},
"id": "node-respond",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
2020,
300
]
}
],
"connections": {
"Webhook - Audio/Notes Upload": {
"main": [
[
{
"node": "Code - Parse Input Type",
"type": "main",
"index": 0
}
]
]
},
"Code - Parse Input Type": {
"main": [
[
{
"node": "IF - Audio Input?",
"type": "main",
"index": 0
}
]
]
},
"IF - Audio Input?": {
"main": [
[
{
"node": "HTTP - Whisper Transcription",
"type": "main",
"index": 0
}
],
[
{
"node": "Code - Merge Transcript",
"type": "main",
"index": 0
}
]
]
},
"HTTP - Whisper Transcription": {
"main": [
[
{
"node": "Code - Merge Transcript",
"type": "main",
"index": 0
}
]
]
},
"Code - Merge Transcript": {
"main": [
[
{
"node": "GPT-4o - Analyze Meeting",
"type": "main",
"index": 0
}
]
]
},
"GPT-4o - Analyze Meeting": {
"main": [
[
{
"node": "Code - Parse & Format Analysis",
"type": "main",
"index": 0
}
]
]
},
"Code - Parse & Format Analysis": {
"main": [
[
{
"node": "Notion - Create Meeting Page",
"type": "main",
"index": 0
}
]
]
},
"Notion - Create Meeting Page": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "meetings"
},
{
"name": "ai"
},
{
"name": "notion"
},
{
"name": "productivity"
}
],
"meta": {
"description": "Upload audio recording or text transcript via webhook \u2192 Whisper transcribes audio \u2192 GPT-4o extracts summary/action items/decisions \u2192 creates structured Notion page with full transcript and formatted action items.",
"prerequisites": [
"OpenAI API key (Whisper + GPT-4o)",
"Notion integration with meetings database access",
"Notion database with: Date, Project, Attendees, Duration, Action Items Count (number), Next Meeting",
"Set OPENAI_API_KEY env variable",
"Audio formats supported by Whisper: mp3, mp4, wav, m4a, webm (max 25MB)"
],
"testingScenario": {
"text_test_payload": {
"title": "Q2 Planning",
"date": "2026-06-13",
"attendees": "Santoshi, Alex, Jordan",
"project": "The AI Stack",
"transcript": "Santoshi: Let's discuss the Q2 roadmap. Alex: I think we need to prioritize the newsletter automation. Jordan: Agreed. I'll own that by June 20th. Santoshi: Great. Let's also fix the lead routing bug. Jordan can handle that too, due June 17th. Any blockers? Alex: We're waiting on API keys from Beehiiv. That's blocking the newsletter work. Next meeting: June 20th 10 AM."
}
}
}
}
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.
notionApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
14 - AI Meeting Notes → Action Items → Notion. Uses httpRequest, openAi, notion. Webhook trigger; 9 nodes.
Source: https://github.com/satmakuru222/TheAIStackk/blob/main/n8n-workflows/14-ai-meeting-notes-action-items-notion.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.
📦 n8n Template Submission – “7-Day Content Bloom” by Shelly-Ann Davy, The Workflow Muse
How It Works
This workflow captures new leads via webhook, enriches and scores them with Apollo and Google Gemini, logs everything in Google Sheets, and automates outreach, reply handling, follow-ups, meeting prep
This powerful n8n automation workflow is designed to execute advanced B2B lead enrichment and hyper-personalization for cold email outreach. By orchestrating a complex chain of data scraping, AI analy
Propulsar — Content Engine v3. Uses openAi, httpRequest, googleSheets. Webhook trigger; 73 nodes.