This workflow corresponds to n8n.io template #skynetlabs-12 — we link there as the canonical source.
This workflow follows the HTTP Request → Slack 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": "12 - Meeting to Action Items to ClickUp",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "meeting-recap",
"responseMode": "lastNode",
"options": {}
},
"id": "trigger-webhook",
"name": "Fathom / Fireflies webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
200,
300
]
},
{
"parameters": {
"jsCode": "const body = $input.first().json.body || $input.first().json;\nconst transcript = body.transcript || body.summary?.transcript || body.meeting?.transcript || '';\nconst title = body.title || body.meeting?.title || 'Untitled meeting';\nconst recording_url = body.share_url || body.recording_url || body.meeting?.url || '';\nconst started_at = body.start_time || body.meeting?.start_time || new Date().toISOString();\nconst attendees = (body.attendees || body.meeting?.attendees || []).map(a => a.name || a.display_name || a.email).filter(Boolean);\nif (!transcript) throw new Error('No transcript in payload');\nreturn [{ json: { title, transcript, recording_url, started_at, attendees } }];"
},
"id": "normalise",
"name": "Normalise payload",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
420,
300
]
},
{
"parameters": {
"modelId": {
"__rl": true,
"value": "claude-sonnet-4-6",
"mode": "list"
},
"messages": {
"values": [
{
"content": "=You extract action items from meeting transcripts. Return ONLY valid JSON.\n\nMeeting: {{ $json.title }}\nAttendees: {{ $json.attendees.join(', ') }}\nStarted: {{ $json.started_at }}\n\nTranscript:\n{{ $json.transcript }}\n\nReturn:\n{\n \"recap\": \"3-4 sentence summary of what was decided\",\n \"tasks\": [\n {\n \"title\": \"verb-first task name, max 80 chars\",\n \"owner_name\": \"first name from attendee list, or 'unassigned'\",\n \"due\": \"YYYY-MM-DD or empty if not stated\",\n \"priority\": \"urgent|high|normal|low\",\n \"context\": \"one sentence why this matters\"\n }\n ],\n \"open_questions\": [\"questions raised but not answered\"]\n}\n\nRules:\n- Only items that have a clear owner or implied owner. No vague 'team should consider'\n- Verbs first: 'Send', 'Draft', 'Review', 'Schedule'\n- If a date like 'by Friday' was said, resolve it relative to the meeting date",
"role": "user"
}
]
},
"options": {
"temperature": 0.2,
"maxTokens": 1800
}
},
"id": "claude-extract",
"name": "Claude extract actions",
"type": "@n8n/n8n-nodes-langchain.anthropic",
"typeVersion": 1.2,
"position": [
640,
300
],
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const NAME_TO_ID = {\n 'waseem': 12345001,\n 'sara': 12345002,\n 'omar': 12345003,\n 'ayesha': 12345004,\n 'naeem': 12345005\n};\nconst raw = $input.first().json.content?.[0]?.text || $input.first().json.text || '';\nconst match = raw.match(/\\{[\\s\\S]*\\}/);\nif (!match) throw new Error('No JSON');\nconst parsed = JSON.parse(match[0]);\nconst meta = $('Normalise payload').first().json;\nconst tasks = (parsed.tasks || []).map(t => ({\n ...t,\n clickup_user_id: NAME_TO_ID[(t.owner_name || '').toLowerCase().trim()] || null,\n meeting_title: meta.title,\n recording_url: meta.recording_url\n}));\nreturn [{ json: { recap: parsed.recap, open_questions: parsed.open_questions || [], tasks, meeting_title: meta.title, recording_url: meta.recording_url } }];"
},
"id": "map-owners",
"name": "Map owners to ClickUp IDs",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
860,
300
]
},
{
"parameters": {
"fieldToSplitOut": "tasks",
"options": {}
},
"id": "split-tasks",
"name": "Split tasks",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
1080,
300
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.clickup.com/api/v2/list/REPLACE_ME_CLICKUP_LIST_ID/task",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"name\": \"{{ $json.title }}\",\n \"description\": \"From meeting: {{ $json.meeting_title }}\\n\\nWhy: {{ $json.context }}\\n\\nRecording: {{ $json.recording_url }}\",\n \"assignees\": [{{ $json.clickup_user_id || 0 }}],\n \"priority\": {{ {urgent:1, high:2, normal:3, low:4}[$json.priority] || 3 }},\n \"due_date\": {{ $json.due ? new Date($json.due).getTime() : 'null' }}\n}",
"options": {}
},
"id": "clickup-create",
"name": "Create ClickUp task",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1300,
300
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"channel": "#meeting-recaps",
"text": "=:memo: *{{ $('Map owners to ClickUp IDs').first().json.meeting_title }}*\n\n{{ $('Map owners to ClickUp IDs').first().json.recap }}\n\n*Action items:* {{ $('Map owners to ClickUp IDs').first().json.tasks.length }} created in ClickUp\n*Open questions:*\n{{ $('Map owners to ClickUp IDs').first().json.open_questions.map(q => '\u2022 ' + q).join('\\n') }}\n\n<{{ $('Map owners to ClickUp IDs').first().json.recording_url }}|Recording>",
"otherOptions": {}
},
"id": "slack-recap",
"name": "Slack recap",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
1520,
300
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Fathom / Fireflies webhook": {
"main": [
[
{
"node": "Normalise payload",
"type": "main",
"index": 0
}
]
]
},
"Normalise payload": {
"main": [
[
{
"node": "Claude extract actions",
"type": "main",
"index": 0
}
]
]
},
"Claude extract actions": {
"main": [
[
{
"node": "Map owners to ClickUp IDs",
"type": "main",
"index": 0
}
]
]
},
"Map owners to ClickUp IDs": {
"main": [
[
{
"node": "Split tasks",
"type": "main",
"index": 0
}
]
]
},
"Split tasks": {
"main": [
[
{
"node": "Create ClickUp task",
"type": "main",
"index": 0
}
]
]
},
"Create ClickUp task": {
"main": [
[
{
"node": "Slack recap",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"meta": {
"templateId": "skynetlabs-12"
},
"tags": [
{
"name": "skynetlabs-pack"
},
{
"name": "meetings"
},
{
"name": "clickup"
}
]
}
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.
anthropicApihttpHeaderAuthslackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
12 - Meeting to Action Items to ClickUp. Uses anthropic, httpRequest, slack. Webhook trigger; 7 nodes.
Source: https://github.com/waseemnasir2k26/skynet-automation-pack/blob/main/n8n/12-meeting-action-items-clickup.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.
Auto-Fix Production Errors with Claude. Uses anthropic, httpRequest, slack, emailSend. Webhook trigger; 10 nodes.
02 - Inbound Form AI Qualifier. Uses httpRequest, anthropic, hubspot, slack. Webhook trigger; 9 nodes.
10 - FAQ -> schema -> WP REST inject. Uses httpRequest, anthropic, slack. Webhook trigger; 8 nodes.
08 - YouTube transcript -> 9 assets. Uses httpRequest, anthropic, googleDocs, notion. Webhook trigger; 7 nodes.
14 - Loom Auto-Doc to Slack. Uses httpRequest, anthropic, slack. Webhook trigger; 7 nodes.