This workflow corresponds to n8n.io template #15106 — we link there as the canonical source.
This workflow follows the Google Sheets → HTTP Request 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 →
{
"nodes": [
{
"id": "5457de76-b93f-4edc-83c1-a88d1b2ecda3",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
-416
],
"parameters": {
"width": 604,
"height": 1208,
"content": "## Sales Call Training Clips \u2014 Fireflies + WayinVideo + Sheets + Slack\n\nFor sales managers and revenue teams who want to automatically extract the best training moments from every sales call. When Fireflies finishes transcribing a call, this workflow takes the recorded video URL, submits it to the WayinVideo Find Moments API with a natural language query, waits for processing, and logs every matching clip with its timestamp, score, and description to Google Sheets. A Slack notification fires once \u2014 after all clips are saved \u2014 with a formatted breakdown for the team.\n\n## How it works\n- **1. Webhook \u2014 Fireflies Transcript Done** receives the meetingId when Fireflies finishes transcribing\n- **2. Set \u2014 Config Values** stores API keys, Sheet ID, Slack channel, the Find Moments query, and max clips\n- **3. HTTP \u2014 Fetch Transcript** fetches the Fireflies transcript including video_url for the recording\n- **4. Code \u2014 Extract Video URL** prefers video_url over audio_url \u2014 throws an error if neither is available\n- **5. HTTP \u2014 Submit Find Moments Task** submits the video to WayinVideo with your natural language query \u2014 returns a project ID\n- **6. Code \u2014 Save Project ID** stores the project ID and initializes the poll counter\n- **7. Wait \u2014 45 Seconds** pauses before the first status check\n- **8. HTTP \u2014 Poll Find Moments Results** checks WayinVideo for the current processing status\n- **9. Code \u2014 Check Status** routes: SUCCEEDED moves forward, FAILED throws an error, anything else loops back \u2014 times out after 20 polls (15 minutes)\n- **10. IF \u2014 Processing Complete?** gates the retry loop\n- **12. Code \u2014 Process Clips** sorts clips by score, converts millisecond timestamps to MM:SS, builds sheet rows and the Slack message\n- **13. Code \u2014 Split Rows for Sheets** splits the clips array to one item per row and marks the last clip\n- **14. Google Sheets \u2014 Log Training Clips** appends one row per clip to the tracker\n- **15. IF \u2014 Last Clip Logged?** ensures Slack fires exactly once after all rows are saved\n- **16. Slack \u2014 Send Training Clips Alert** sends the full clip breakdown to your sales training channel\n\n## Set up steps\n1. Activate the workflow and copy the webhook URL from node 1\n2. In Fireflies \u2014 go to Settings, Developer Settings, Webhooks, and paste the URL\n3. In **2. Set \u2014 Config Values** \u2014 replace YOUR_FIREFLIES_API_KEY, YOUR_WAYINVIDEO_API_KEY, YOUR_GOOGLE_SHEET_ID, Slack channel, and customize findMomentsQuery for your use case\n4. In **14. Google Sheets \u2014 Log Training Clips** \u2014 connect your Google Sheets OAuth2 credential\n5. In **16. Slack \u2014 Send Training Clips Alert** \u2014 connect your Slack OAuth2 credential and invite the bot to your channel\n6. Create a Google Sheet tab named Sales Training Clips with columns: Date, Meeting Title, Clip #, Clip Title, Start, End, Duration (sec), Score, Tags, Description, Logged At"
},
"typeVersion": 1
},
{
"id": "65f3ba29-31ba-4c17-a398-43fee7d4881e",
"name": "Section \u2014 Webhook, Config, and Fireflies Fetch",
"type": "n8n-nodes-base.stickyNote",
"position": [
-32,
-64
],
"parameters": {
"color": 5,
"width": 644,
"height": 484,
"content": "## Webhook, Config, and Fireflies Fetch\nFireflies POSTs a meetingId here on transcription complete. Config stores both API keys, sheet and Slack settings, the Find Moments query, and max clips. HTTP fetches the Fireflies transcript including the video recording URL."
},
"typeVersion": 1
},
{
"id": "999152ec-e6af-46b7-b5fd-f23dfcee4a29",
"name": "Section \u2014 Video URL Extraction and WayinVideo Submission",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
-80
],
"parameters": {
"color": 6,
"width": 612,
"height": 500,
"content": "## Video URL Extraction and WayinVideo Submission\nExtracts video_url (preferred) or audio_url (fallback) from Fireflies. Throws an error if neither is available. Submits to WayinVideo Find Moments API with the natural language query. Saves the returned project ID for polling."
},
"typeVersion": 1
},
{
"id": "deea1a6e-6e60-4621-98c5-add7633b2540",
"name": "Section \u2014 WayinVideo Polling and Retry Loop",
"type": "n8n-nodes-base.stickyNote",
"position": [
1328,
-144
],
"parameters": {
"color": 6,
"width": 900,
"height": 724,
"content": "## WayinVideo Polling and Retry Loop\nWaits 45 seconds then polls the Find Moments endpoint. SUCCEEDED moves forward. FAILED throws an error. Still processing loops back to Wait. Hard timeout after 20 polls (approximately 15 minutes)."
},
"typeVersion": 1
},
{
"id": "dd0cbf23-2ffd-402e-baec-e685b3e973ff",
"name": "Section \u2014 Clip Processing, Sheet Logging, and Slack Alert",
"type": "n8n-nodes-base.stickyNote",
"position": [
2368,
-240
],
"parameters": {
"color": 4,
"width": 1060,
"height": 500,
"content": "## Clip Processing, Sheet Logging, and Slack Alert\nSorts clips by relevance score, converts timestamps to MM:SS, and splits into one item per clip for the logging loop. Google Sheets logs each clip as a separate row. Slack fires exactly once after all clips are logged \u2014 the isLastRow gate prevents duplicate alerts."
},
"typeVersion": 1
},
{
"id": "4049ec0f-2494-4f83-b5df-b345984a0ed1",
"name": "1. Webhook \u2014 Fireflies Transcript Done",
"type": "n8n-nodes-base.webhook",
"position": [
16,
144
],
"parameters": {
"path": "fireflies-sales-clips",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 1.1
},
{
"id": "3fb1ee35-78f1-4247-b9b0-efe172a78a60",
"name": "2. Set \u2014 Config Values",
"type": "n8n-nodes-base.set",
"position": [
240,
144
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "cfg-001",
"name": "firefliesApiKey",
"type": "string",
"value": "YOUR_FIREFLIES_API_KEY"
},
{
"id": "cfg-002",
"name": "wayinVideoApiKey",
"type": "string",
"value": "YOUR_WAYINVIDEO_API_KEY"
},
{
"id": "cfg-003",
"name": "sheetId",
"type": "string",
"value": "YOUR_GOOGLE_SHEET_ID"
},
{
"id": "cfg-004",
"name": "sheetName",
"type": "string",
"value": "Sales Training Clips"
},
{
"id": "cfg-005",
"name": "slackChannel",
"type": "string",
"value": "#sales-training"
},
{
"id": "cfg-006",
"name": "findMomentsQuery",
"type": "string",
"value": "objection handling and rebuttal moments"
},
{
"id": "cfg-007",
"name": "maxClips",
"type": "string",
"value": "3"
},
{
"id": "cfg-008",
"name": "meetingId",
"type": "string",
"value": "={{ $json.meetingId || $json.body?.meetingId || $json.data?.meetingId || '' }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "98052d94-fd14-4a06-9bf3-41b4253b39e5",
"name": "3. HTTP \u2014 Fetch Transcript",
"type": "n8n-nodes-base.httpRequest",
"position": [
464,
144
],
"parameters": {
"url": "https://api.fireflies.ai/graphql",
"method": "POST",
"options": {},
"jsonBody": "={\n \"query\": \"query GetTranscript($id: String!) { transcript(id: $id) { id title date duration participants video_url audio_url transcript_url summary { keywords overview } } }\",\n \"variables\": {\n \"id\": \"{{ $json.meetingId }}\"\n }\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Authorization",
"value": "=Bearer {{ $json.firefliesApiKey }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "6c46c048-ba7f-4d4e-8630-b4b9d5a71700",
"name": "4. Code \u2014 Extract Video URL",
"type": "n8n-nodes-base.code",
"position": [
688,
144
],
"parameters": {
"jsCode": "const response = $input.first().json;\nconst config = $('2. Set \u2014 Config Values').item.json;\n\nconst t = response?.data?.transcript;\nif (!t || !t.id) throw new Error('Transcript not found for meetingId: ' + config.meetingId);\n\nconst videoUrl = t.video_url || '';\nconst audioUrl = t.audio_url || '';\nconst mediaUrl = videoUrl || audioUrl;\n\nif (!mediaUrl) {\n throw new Error(\n 'No video_url or audio_url available for meeting: ' + (t.title || t.id) +\n '. Make sure Fireflies bot joined and recorded the meeting.'\n );\n}\n\nconst meetingDate = t.date\n ? new Date(t.date).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })\n : new Date().toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });\n\nconst keywords = (t.summary?.keywords || []).slice(0, 8).join(', ');\nconst overview = (t.summary?.overview || '').substring(0, 400);\n\nreturn [{\n json: {\n meetingId: t.id,\n meetingTitle: t.title || 'Untitled Meeting',\n meetingDate,\n durationMin: Math.round((t.duration || 0) / 60),\n participants: (t.participants || []).join(', ') || 'Unknown',\n mediaUrl,\n isVideo: !!videoUrl,\n transcriptUrl: t.transcript_url || '',\n keywords,\n overview,\n wayinVideoApiKey: config.wayinVideoApiKey,\n sheetId: config.sheetId,\n sheetName: config.sheetName,\n slackChannel: config.slackChannel,\n findMomentsQuery: config.findMomentsQuery,\n maxClips: parseInt(config.maxClips) || 3\n }\n}];"
},
"typeVersion": 2
},
{
"id": "590c5246-6463-46f4-aebe-34053d8b52c7",
"name": "5. HTTP \u2014 Submit Find Moments Task",
"type": "n8n-nodes-base.httpRequest",
"position": [
896,
144
],
"parameters": {
"url": "https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments",
"method": "POST",
"options": {},
"jsonBody": "={\n \"video_url\": \"{{ $json.mediaUrl }}\",\n \"query\": \"{{ $json.findMomentsQuery }}\",\n \"project_name\": \"{{ $json.meetingTitle }} \u2014 Training Clips\",\n \"limit\": {{ $json.maxClips }},\n \"enable_export\": false\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Authorization",
"value": "=Bearer {{ $json.wayinVideoApiKey }}"
},
{
"name": "x-wayinvideo-api-version",
"value": "v2"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "23b6889b-1f97-4ae8-96bf-fe119f3f2e02",
"name": "6. Code \u2014 Save Project ID",
"type": "n8n-nodes-base.code",
"position": [
1120,
144
],
"parameters": {
"jsCode": "const response = $input.first().json;\nconst prev = $('4. Code \u2014 Extract Video URL').item.json;\n\nconst projectId = response?.data?.id;\nif (!projectId) throw new Error('WayinVideo did not return a project ID. Check API key and video URL.');\n\nreturn [{\n json: {\n projectId,\n status: response.data.status || 'CREATED',\n meetingTitle: prev.meetingTitle,\n meetingDate: prev.meetingDate,\n durationMin: prev.durationMin,\n participants: prev.participants,\n mediaUrl: prev.mediaUrl,\n transcriptUrl: prev.transcriptUrl,\n keywords: prev.keywords,\n wayinVideoApiKey: prev.wayinVideoApiKey,\n sheetId: prev.sheetId,\n sheetName: prev.sheetName,\n slackChannel: prev.slackChannel,\n findMomentsQuery: prev.findMomentsQuery,\n maxClips: prev.maxClips,\n pollCount: 0\n }\n}];"
},
"typeVersion": 2
},
{
"id": "3b3e3676-f0f7-4601-861f-2e0ff5e213b1",
"name": "7. Wait \u2014 45 Seconds",
"type": "n8n-nodes-base.wait",
"position": [
1376,
128
],
"parameters": {
"amount": 45
},
"typeVersion": 1.1
},
{
"id": "2d821d57-24c5-4182-9fc1-1c2c7d5737b0",
"name": "8. HTTP \u2014 Poll Find Moments Results",
"type": "n8n-nodes-base.httpRequest",
"position": [
1600,
128
],
"parameters": {
"url": "=https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments/results/{{ $json.projectId }}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.wayinVideoApiKey }}"
},
{
"name": "x-wayinvideo-api-version",
"value": "v2"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "45ec6375-e5ed-42bb-a2f4-006843f05d9e",
"name": "9. Code \u2014 Check Status",
"type": "n8n-nodes-base.code",
"position": [
1808,
128
],
"parameters": {
"jsCode": "const pollResponse = $input.first().json;\nconst prev = $('6. Code \u2014 Save Project ID').item.json;\n\nconst status = pollResponse?.data?.status || 'UNKNOWN';\nconst pollCount = (prev.pollCount || 0) + 1;\n\nif (pollCount >= 20 && status !== 'SUCCEEDED') {\n throw new Error('WayinVideo timeout after 20 polls (~15 min). Project: ' + prev.projectId);\n}\n\nif (status === 'FAILED') {\n throw new Error('WayinVideo processing failed: ' + (pollResponse?.data?.error_message || 'Unknown error'));\n}\n\nreturn [{\n json: {\n projectId: prev.projectId,\n status,\n clips: pollResponse?.data?.clips || [],\n pollCount,\n isReady: status === 'SUCCEEDED',\n meetingTitle: prev.meetingTitle,\n meetingDate: prev.meetingDate,\n durationMin: prev.durationMin,\n participants: prev.participants,\n transcriptUrl: prev.transcriptUrl,\n keywords: prev.keywords,\n wayinVideoApiKey: prev.wayinVideoApiKey,\n sheetId: prev.sheetId,\n sheetName: prev.sheetName,\n slackChannel: prev.slackChannel,\n findMomentsQuery: prev.findMomentsQuery,\n maxClips: prev.maxClips\n }\n}];"
},
"typeVersion": 2
},
{
"id": "d0d80d44-80be-43fe-95e6-73f09d11f1f4",
"name": "10. IF \u2014 Processing Complete?",
"type": "n8n-nodes-base.if",
"position": [
2032,
128
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": false,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "cond-ready",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.isReady }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "7bec2e62-b33f-4823-ad13-798d6965e9fb",
"name": "11. Set \u2014 Still Processing",
"type": "n8n-nodes-base.set",
"position": [
2032,
336
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "loop-001",
"name": "result",
"type": "string",
"value": "Still processing \u2014 looping back to Wait."
}
]
}
},
"typeVersion": 3.4
},
{
"id": "b6b03d81-8285-4313-b1ce-892440c99f24",
"name": "12. Code \u2014 Process Clips",
"type": "n8n-nodes-base.code",
"position": [
2416,
-16
],
"parameters": {
"jsCode": "const data = $input.first().json;\nconst clips = data.clips || [];\n\nif (clips.length === 0) {\n throw new Error('WayinVideo returned no clips. The query may not match any moments in this video.');\n}\n\nconst topClips = [...clips]\n .sort((a, b) => (b.score || 0) - (a.score || 0))\n .slice(0, data.maxClips || 3);\n\nconst msToTime = (ms) => {\n const totalSecs = Math.floor((ms || 0) / 1000);\n const mins = Math.floor(totalSecs / 60);\n const secs = totalSecs % 60;\n return mins + ':' + String(secs).padStart(2, '0');\n};\n\nconst loggedAt = new Date().toISOString().replace('T', ' ').substring(0, 16);\n\nconst sheetRows = topClips.map((clip, i) => ({\n date: data.meetingDate,\n meetingTitle: data.meetingTitle,\n clipNum: (i + 1),\n clipTitle: clip.title || 'Untitled Clip',\n startTime: msToTime(clip.begin_ms),\n endTime: msToTime(clip.end_ms),\n durationSec: Math.round(((clip.end_ms || 0) - (clip.begin_ms || 0)) / 1000),\n score: clip.score || 0,\n tags: (clip.tags || []).join(', '),\n description: (clip.desc || '').substring(0, 200),\n loggedAt,\n sheetId: data.sheetId,\n sheetName: data.sheetName\n}));\n\nlet clipLines = '';\ntopClips.forEach((clip, i) => {\n const duration = Math.round(((clip.end_ms || 0) - (clip.begin_ms || 0)) / 1000);\n clipLines +=\n (i + 1) + '. *' + (clip.title || 'Clip ' + (i + 1)) + '* \u2014 ' +\n msToTime(clip.begin_ms) + ' to ' + msToTime(clip.end_ms) +\n ' (' + duration + 's) | Score: ' + (clip.score || 0) + '/100\\n' +\n ' ' + (clip.desc || '').substring(0, 100) + '\\n';\n});\n\nconst slackMessage =\n '*New Sales Training Clips*\\n\\n' +\n '*Meeting:* ' + data.meetingTitle + '\\n' +\n '*Date:* ' + data.meetingDate + ' | *Duration:* ' + data.durationMin + ' min\\n' +\n '*Query:* _' + data.findMomentsQuery + '_\\n' +\n '*Clips Found:* ' + topClips.length + '\\n\\n' +\n clipLines +\n '\\n_Full recording: ' + (data.transcriptUrl || 'See Fireflies') + '_';\n\nreturn [{\n json: {\n sheetRows,\n slackMessage,\n slackChannel: data.slackChannel,\n totalClips: topClips.length\n }\n}];"
},
"typeVersion": 2
},
{
"id": "2213133a-d74d-4973-b20c-e19f69b0abc1",
"name": "13. Code \u2014 Split Rows for Sheets",
"type": "n8n-nodes-base.code",
"position": [
2640,
-16
],
"parameters": {
"jsCode": "const data = $input.first().json;\nconst rows = data.sheetRows || [];\n\nreturn rows.map((row, i) => ({\n json: {\n ...row,\n isLastRow: i === rows.length - 1,\n slackMessage: data.slackMessage,\n slackChannel: data.slackChannel\n }\n}));"
},
"typeVersion": 2
},
{
"id": "19d4cf52-5919-43eb-9ac6-b69ba43ccfd7",
"name": "14. Google Sheets \u2014 Log Training Clips",
"type": "n8n-nodes-base.googleSheets",
"position": [
2848,
-16
],
"parameters": {
"columns": {
"value": {
"End": "={{ $json.endTime }}",
"Date": "={{ $json.date }}",
"Tags": "={{ $json.tags }}",
"Score": "={{ $json.score }}",
"Start": "={{ $json.startTime }}",
"Clip #": "={{ $json.clipNum }}",
"Logged At": "={{ $json.loggedAt }}",
"Clip Title": "={{ $json.clipTitle }}",
"Description": "={{ $json.description }}",
"Meeting Title": "={{ $json.meetingTitle }}",
"Duration (sec)": "={{ $json.durationSec }}"
},
"mappingMode": "defineBelow"
},
"options": {
"cellFormat": "USER_ENTERED"
},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $json.sheetName }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.sheetId }}"
}
},
"typeVersion": 4.5
},
{
"id": "630afcbc-0625-4112-941d-6b3451bc0c41",
"name": "15. IF \u2014 Last Clip Logged?",
"type": "n8n-nodes-base.if",
"position": [
3072,
-16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": false,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "cond-last",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.isLastRow }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "cbe98f00-6271-4166-9357-554f3e58dcc5",
"name": "16. Slack \u2014 Send Training Clips Alert",
"type": "n8n-nodes-base.slack",
"position": [
3296,
-176
],
"parameters": {
"text": "={{ $json.slackMessage }}",
"otherOptions": {
"mrkdwn": true
},
"authentication": "oAuth2"
},
"typeVersion": 2.2
},
{
"id": "d42ece7d-abfc-4c12-a223-c3336cb89a47",
"name": "17. Set \u2014 More Clips",
"type": "n8n-nodes-base.set",
"position": [
3296,
144
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "more-001",
"name": "result",
"type": "string",
"value": "More clips being logged \u2014 loop continues."
}
]
}
},
"typeVersion": 3.4
}
],
"connections": {
"7. Wait \u2014 45 Seconds": {
"main": [
[
{
"node": "8. HTTP \u2014 Poll Find Moments Results",
"type": "main",
"index": 0
}
]
]
},
"2. Set \u2014 Config Values": {
"main": [
[
{
"node": "3. HTTP \u2014 Fetch Transcript",
"type": "main",
"index": 0
}
]
]
},
"9. Code \u2014 Check Status": {
"main": [
[
{
"node": "10. IF \u2014 Processing Complete?",
"type": "main",
"index": 0
}
]
]
},
"12. Code \u2014 Process Clips": {
"main": [
[
{
"node": "13. Code \u2014 Split Rows for Sheets",
"type": "main",
"index": 0
}
]
]
},
"6. Code \u2014 Save Project ID": {
"main": [
[
{
"node": "7. Wait \u2014 45 Seconds",
"type": "main",
"index": 0
}
]
]
},
"11. Set \u2014 Still Processing": {
"main": [
[
{
"node": "7. Wait \u2014 45 Seconds",
"type": "main",
"index": 0
}
]
]
},
"15. IF \u2014 Last Clip Logged?": {
"main": [
[
{
"node": "16. Slack \u2014 Send Training Clips Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "17. Set \u2014 More Clips",
"type": "main",
"index": 0
}
]
]
},
"3. HTTP \u2014 Fetch Transcript": {
"main": [
[
{
"node": "4. Code \u2014 Extract Video URL",
"type": "main",
"index": 0
}
]
]
},
"4. Code \u2014 Extract Video URL": {
"main": [
[
{
"node": "5. HTTP \u2014 Submit Find Moments Task",
"type": "main",
"index": 0
}
]
]
},
"10. IF \u2014 Processing Complete?": {
"main": [
[
{
"node": "12. Code \u2014 Process Clips",
"type": "main",
"index": 0
}
],
[
{
"node": "11. Set \u2014 Still Processing",
"type": "main",
"index": 0
}
]
]
},
"13. Code \u2014 Split Rows for Sheets": {
"main": [
[
{
"node": "14. Google Sheets \u2014 Log Training Clips",
"type": "main",
"index": 0
}
]
]
},
"5. HTTP \u2014 Submit Find Moments Task": {
"main": [
[
{
"node": "6. Code \u2014 Save Project ID",
"type": "main",
"index": 0
}
]
]
},
"8. HTTP \u2014 Poll Find Moments Results": {
"main": [
[
{
"node": "9. Code \u2014 Check Status",
"type": "main",
"index": 0
}
]
]
},
"1. Webhook \u2014 Fireflies Transcript Done": {
"main": [
[
{
"node": "2. Set \u2014 Config Values",
"type": "main",
"index": 0
}
]
]
},
"14. Google Sheets \u2014 Log Training Clips": {
"main": [
[
{
"node": "15. IF \u2014 Last Clip Logged?",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Connect Fireflies and WayinVideo to this workflow once and every recorded sales call automatically generates a set of training clips delivered to your Slack channel. The moment Fireflies finishes transcribing a call, the workflow takes the video recording, submits it to…
Source: https://n8n.io/workflows/15106/ — 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.
This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS
Turn every sales meeting into a coaching opportunity. This workflow automatically analyzes tldv meeting recordings using OpenAI (GPT-4) to provide instant, actionable feedback to your sales team.
Automated video processing system that monitors S3 for new uploads, generates thumbnails and preview clips, extracts metadata, transcodes to multiple formats, and distributes to CDN with webhook notif
Eliminate manual data entry from your accounts payable process. This workflow transforms raw invoice scans into structured financial records by combining UploadToURL for hosting, AWS Textract for OCR
Invoice Data Extraction. Uses httpRequest, slack, googleSheets, errorTrigger. Webhook trigger; 16 nodes.