AutomationFlowsAI & RAG › Create AI Proposals From Fireflies Transcripts with Gpt-4o, Google Docs,…

Create AI Proposals From Fireflies Transcripts with Gpt-4o, Google Docs,…

Original n8n title: Create AI Proposals From Fireflies Transcripts with Gpt-4o, Google Docs, Gmail and Telegram Approval

ByDevon Toh @devontoh on n8n.io

Listens for completed Fireflies transcripts, qualifies whether a proposal is needed using OpenAI, drafts structured proposal content, populates a Google Doc template, converts to PDF, and sends it to the client via Gmail after you approve it in Telegram.

Webhook trigger★★★★★ complexityAI-powered32 nodesHTTP RequestOpenAIGoogle DriveGoogle DocsTelegramGmail
AI & RAG Trigger: Webhook Nodes: 32 Complexity: ★★★★★ AI nodes: yes Added:
Create AI Proposals From Fireflies Transcripts with Gpt-4o, Google Docs,… — n8n workflow card showing HTTP Request, OpenAI, Google Drive integration

This workflow corresponds to n8n.io template #14717 — we link there as the canonical source.

This workflow follows the Gmail → Google Docs 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 →

Download .json
{
  "id": "ySNUgic8v2IM1UGH",
  "name": "Fireflies Meeting Transcript to Auto-Proposal with Telegram Approval and Gmail Delivery",
  "tags": [],
  "nodes": [
    {
      "id": "node-1",
      "name": "When Transcript Ready",
      "type": "n8n-nodes-base.webhook",
      "position": [
        0,
        288
      ],
      "parameters": {
        "path": "fireflies-transcript",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "node-2",
      "name": "Respond 200 OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        224,
        288
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\"status\": \"received\", \"message\": \"Transcript processing started\"}"
      },
      "typeVersion": 1
    },
    {
      "id": "node-3",
      "name": "Get Full Transcript",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 3,
      "position": [
        448,
        288
      ],
      "parameters": {
        "url": "https://api.fireflies.ai/graphql",
        "method": "POST",
        "options": {
          "timeout": 30000
        },
        "jsonBody": "={\n  \"query\": \"query GetTranscript($transcriptId: String!) { transcript(id: $transcriptId) { id title date duration organizer_email participants { name email } sentences { text speaker_name } action_items summary { overview shorthand_bullet } } }\",\n  \"variables\": { \"transcriptId\": \"{{ $json.body.meetingId || $json.body.transcriptId }}\" }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "waitBetweenTries": 2000
    },
    {
      "id": "node-4",
      "name": "If Transcript Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        672,
        288
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-1",
              "operator": {
                "type": "object",
                "operation": "exists"
              },
              "leftValue": "={{ $json.data.transcript }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "node-5",
      "name": "Classify Meeting Type",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        896,
        192
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o"
        },
        "options": {
          "temperature": 0.2
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a meeting analyst. Analyze the meeting transcript and determine if this meeting requires a follow-up proposal to be sent to the client.\n\nA proposal is needed when:\n- Services, pricing, or project scope was discussed\n- The client expressed interest in hiring or engaging for work\n- Next steps involve sending a quote, estimate, or proposal\n- There was a discovery/sales call\n\nA proposal is NOT needed when:\n- Internal team meetings\n- Status updates or check-ins\n- Social/casual conversations\n- Support/troubleshooting calls\n\nRespond in this exact JSON format:\n{\n  \"needs_proposal\": true/false,\n  \"reason\": \"Brief explanation\",\n  \"client_name\": \"Name or null\",\n  \"client_email\": \"Email or null\",\n  \"client_company\": \"Company or null\",\n  \"meeting_summary\": \"2-3 sentence summary of what was discussed\",\n  \"key_points\": [\"point 1\", \"point 2\"],\n  \"services_discussed\": [\"service 1\", \"service 2\"],\n  \"client_pain_points\": [\"pain 1\", \"pain 2\"],\n  \"estimated_scope\": \"Brief scope description or null\",\n  \"follow_up_notes\": \"Any specific things the client mentioned wanting\"\n}"
            },
            {
              "content": "=Meeting Title: {{ $json.data.transcript.title }}\nDate: {{ $json.data.transcript.date }}\nParticipants: {{ JSON.stringify($json.data.transcript.participants) }}\nSummary: {{ $json.data.transcript.summary?.overview || 'No summary available' }}\n\nFull Transcript:\n{{ $json.data.transcript.sentences?.map(s => s.speaker_name + ': ' + s.text).join('\\n') }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "typeVersion": 1.8
    },
    {
      "id": "node-6",
      "name": "If Proposal Needed",
      "type": "n8n-nodes-base.if",
      "position": [
        1248,
        192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-2",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.needs_proposal }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "node-7",
      "name": "Generate Proposal Content",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1472,
        96
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o"
        },
        "options": {
          "temperature": 0.4
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a professional proposal writer. Based on the meeting analysis provided, generate structured proposal content to fill a document template.\n\nReturn a JSON object with these exact keys. Each value should be well-written, professional but conversational text:\n\n{\n  \"CLIENT_NAME\": \"The client's full name\",\n  \"CLIENT_COMPANY\": \"The client's company name or 'your team' if unknown\",\n  \"MEETING_DATE\": \"The date of the meeting in a readable format\",\n  \"MEETING_RECAP\": \"2-3 sentence recap of what was discussed in the meeting\",\n  \"UNDERSTANDING_OF_NEEDS\": \"A paragraph showing clear understanding of the client's pain points and what they need solved. Be specific to what was discussed.\",\n  \"PROPOSED_SOLUTION\": \"A clear description of the proposed approach, broken into phases if applicable. Be specific, not generic.\",\n  \"DELIVERABLES\": \"A bullet-point list of specific deliverables (use newlines between each)\",\n  \"TIMELINE\": \"Estimated timeline for delivery with key milestones\",\n  \"INVESTMENT\": \"[PRICING TO BE CONFIRMED]\",\n  \"NEXT_STEPS\": \"What happens after the client approves - onboarding, kickoff call, etc.\",\n  \"summary_for_review\": \"3-4 sentence summary for the Telegram approval message\"\n}\n\nWrite in a professional but warm, conversational tone. Be specific based on the meeting content. Do not use generic filler."
            },
            {
              "content": "=Meeting Analysis:\nClient: {{ $json.client_name }} ({{ $json.client_company || 'Company not specified' }})\nEmail: {{ $json.client_email || 'Not found' }}\nMeeting Date: {{ $json.meeting_date || 'Not specified' }}\n\nMeeting Summary: {{ $json.meeting_summary }}\n\nKey Points Discussed:\n{{ $json.key_points?.join('\\n- ') }}\n\nServices Discussed:\n{{ $json.services_discussed?.join('\\n- ') }}\n\nClient Pain Points:\n{{ $json.client_pain_points?.join('\\n- ') }}\n\nEstimated Scope: {{ $json.estimated_scope || 'To be determined' }}\n\nFollow-up Notes: {{ $json.follow_up_notes || 'None' }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "typeVersion": 1.8
    },
    {
      "id": "node-8",
      "name": "Prepare Proposal Data",
      "type": "n8n-nodes-base.set",
      "position": [
        1824,
        96
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "set-1",
              "name": "client_name",
              "type": "string",
              "value": "={{ $('Classify Meeting Type').item.json.client_name }}"
            },
            {
              "id": "set-2",
              "name": "client_email",
              "type": "string",
              "value": "={{ $('Classify Meeting Type').item.json.client_email }}"
            },
            {
              "id": "set-3",
              "name": "client_company",
              "type": "string",
              "value": "={{ $('Classify Meeting Type').item.json.client_company }}"
            },
            {
              "id": "set-4",
              "name": "meeting_summary",
              "type": "string",
              "value": "={{ $('Classify Meeting Type').item.json.meeting_summary }}"
            },
            {
              "id": "set-5",
              "name": "services_discussed",
              "type": "string",
              "value": "={{ $('Classify Meeting Type').item.json.services_discussed?.join(', ') }}"
            },
            {
              "id": "set-6",
              "name": "summary_for_review",
              "type": "string",
              "value": "={{ $json.summary_for_review }}"
            },
            {
              "id": "set-7",
              "name": "CLIENT_NAME",
              "type": "string",
              "value": "={{ $json.CLIENT_NAME }}"
            },
            {
              "id": "set-8",
              "name": "CLIENT_COMPANY",
              "type": "string",
              "value": "={{ $json.CLIENT_COMPANY }}"
            },
            {
              "id": "set-9",
              "name": "MEETING_DATE",
              "type": "string",
              "value": "={{ $json.MEETING_DATE }}"
            },
            {
              "id": "set-10",
              "name": "MEETING_RECAP",
              "type": "string",
              "value": "={{ $json.MEETING_RECAP }}"
            },
            {
              "id": "set-11",
              "name": "UNDERSTANDING_OF_NEEDS",
              "type": "string",
              "value": "={{ $json.UNDERSTANDING_OF_NEEDS }}"
            },
            {
              "id": "set-12",
              "name": "PROPOSED_SOLUTION",
              "type": "string",
              "value": "={{ $json.PROPOSED_SOLUTION }}"
            },
            {
              "id": "set-13",
              "name": "DELIVERABLES",
              "type": "string",
              "value": "={{ $json.DELIVERABLES }}"
            },
            {
              "id": "set-14",
              "name": "TIMELINE",
              "type": "string",
              "value": "={{ $json.TIMELINE }}"
            },
            {
              "id": "set-15",
              "name": "INVESTMENT",
              "type": "string",
              "value": "={{ $json.INVESTMENT }}"
            },
            {
              "id": "set-16",
              "name": "NEXT_STEPS",
              "type": "string",
              "value": "={{ $json.NEXT_STEPS }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "node-9",
      "name": "Copy Proposal Template",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2048,
        96
      ],
      "parameters": {
        "name": "=Proposal - {{ $json.CLIENT_NAME }} - {{ $json.CLIENT_COMPANY }} - {{ $json.MEETING_DATE }}",
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "options": {},
        "operation": "copy"
      },
      "typeVersion": 3
    },
    {
      "id": "node-9b",
      "name": "Fill Template Placeholders",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        2272,
        96
      ],
      "parameters": {
        "actionsUi": {
          "actionFields": [
            {
              "text": "{{CLIENT_NAME}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.CLIENT_NAME }}"
            },
            {
              "text": "{{CLIENT_COMPANY}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.CLIENT_COMPANY }}"
            },
            {
              "text": "{{MEETING_DATE}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.MEETING_DATE }}"
            },
            {
              "text": "{{MEETING_RECAP}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.MEETING_RECAP }}"
            },
            {
              "text": "{{UNDERSTANDING_OF_NEEDS}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.UNDERSTANDING_OF_NEEDS }}"
            },
            {
              "text": "{{PROPOSED_SOLUTION}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.PROPOSED_SOLUTION }}"
            },
            {
              "text": "{{DELIVERABLES}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.DELIVERABLES }}"
            },
            {
              "text": "{{TIMELINE}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.TIMELINE }}"
            },
            {
              "text": "{{INVESTMENT}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.INVESTMENT }}"
            },
            {
              "text": "{{NEXT_STEPS}}",
              "action": "replaceAll",
              "matchCase": true,
              "replaceText": "={{ $('Prepare Proposal Data').item.json.NEXT_STEPS }}"
            }
          ]
        },
        "operation": "update"
      },
      "typeVersion": 2
    },
    {
      "id": "node-10",
      "name": "Export Doc as PDF",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 2,
      "position": [
        2496,
        96
      ],
      "parameters": {
        "url": "=https://www.googleapis.com/drive/v3/files/{{ $json.documentId }}/export?mimeType=application/pdf",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "authentication": "oAuth2"
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "node-11",
      "name": "Save PDF to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2720,
        96
      ],
      "parameters": {
        "name": "=Proposal - {{ $('Prepare Proposal Data').item.json.CLIENT_NAME }} - {{ $('Prepare Proposal Data').item.json.CLIENT_COMPANY }}.pdf",
        "driveId": {
          "__rl": true,
          "mode": "id",
          "value": "MyDrive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        }
      },
      "typeVersion": 3
    },
    {
      "id": "node-12",
      "name": "Send Approval Request",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2944,
        96
      ],
      "parameters": {
        "text": "=\ud83d\udccb *NEW PROPOSAL READY FOR REVIEW*\n\n*Client:* {{ $('Prepare Proposal Data').item.json.CLIENT_NAME || 'Unknown' }}\n*Company:* {{ $('Prepare Proposal Data').item.json.CLIENT_COMPANY || 'Not specified' }}\n*Email:* {{ $('Prepare Proposal Data').item.json.client_email || '\u26a0\ufe0f NOT FOUND - you will be asked to provide it' }}\n\n*Services:* {{ $('Prepare Proposal Data').item.json.services_discussed || 'See proposal' }}\n\n*Summary:*\n{{ $('Prepare Proposal Data').item.json.summary_for_review }}\n\n\ud83d\udcc4 [View Proposal Doc](https://docs.google.com/document/d/{{ $('Copy Proposal Template').item.json.id }})\n\n---\nClick below to approve or reject:",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "node-13",
      "name": "Wait for Approval",
      "type": "n8n-nodes-base.wait",
      "position": [
        3168,
        96
      ],
      "parameters": {
        "resume": "webhook",
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "node-14",
      "name": "If Approved",
      "type": "n8n-nodes-base.if",
      "position": [
        3392,
        96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-3",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.query.action }}",
              "rightValue": "approve"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "node-15",
      "name": "If Client Email Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        3616,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-4",
              "operator": {
                "type": "string",
                "operation": "isNotEmpty"
              },
              "leftValue": "={{ $('Prepare Proposal Data').item.json.client_email }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "node-16",
      "name": "Ask for Client Email",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3840,
        80
      ],
      "parameters": {
        "text": "\u26a0\ufe0f Client email was not found in the transcript.\n\nPlease reply with the client's email address:",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "node-17",
      "name": "Wait for Email Reply",
      "type": "n8n-nodes-base.wait",
      "position": [
        4064,
        80
      ],
      "parameters": {
        "resume": "webhook",
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "node-18",
      "name": "Prepare Email Data",
      "type": "n8n-nodes-base.set",
      "position": [
        4288,
        -16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "set-email",
              "name": "final_client_email",
              "type": "string",
              "value": "={{ $('If Client Email Exists').item ? $('Prepare Proposal Data').item.json.client_email : $json.body?.message?.text || $json.query?.email }}"
            },
            {
              "id": "set-name",
              "name": "final_client_name",
              "type": "string",
              "value": "={{ $('Prepare Proposal Data').item.json.CLIENT_NAME || 'there' }}"
            },
            {
              "id": "set-title",
              "name": "final_proposal_title",
              "type": "string",
              "value": "=Proposal - {{ $('Prepare Proposal Data').item.json.CLIENT_NAME }} - {{ $('Prepare Proposal Data').item.json.CLIENT_COMPANY }}"
            },
            {
              "id": "set-summary",
              "name": "final_meeting_summary",
              "type": "string",
              "value": "={{ $('Prepare Proposal Data').item.json.meeting_summary }}"
            },
            {
              "id": "set-pdf-id",
              "name": "pdf_file_id",
              "type": "string",
              "value": "={{ $('Save PDF to Drive').item.json.id }}"
            },
            {
              "id": "set-doc-id",
              "name": "doc_id",
              "type": "string",
              "value": "={{ $('Copy Proposal Template').item.json.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "node-19",
      "name": "Download PDF from Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        4512,
        -16
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.pdf_file_id }}"
        },
        "options": {},
        "operation": "download"
      },
      "typeVersion": 3
    },
    {
      "id": "node-20",
      "name": "Send Proposal Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4736,
        -16
      ],
      "parameters": {
        "sendTo": "={{ $('Prepare Email Data').item.json.final_client_email }}",
        "message": "=Hi {{ $('Prepare Email Data').item.json.final_client_name }},\n\nIt was great speaking with you! I really enjoyed learning more about your goals and the challenges you are working through.\n\nFollowing up on our conversation, I have put together a proposal that outlines how I can help. It covers the key points we discussed, along with a clear breakdown of what the engagement would look like.\n\nI have attached the proposal as a PDF for your review.\n\nPlease take your time going through it. If anything needs adjusting or if you have questions, I am happy to hop on a quick call or chat through it.\n\nLooking forward to hearing your thoughts!\n\nWarm regards",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {}
            ]
          }
        },
        "subject": "={{ $('Prepare Email Data').item.json.final_proposal_title }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "node-21",
      "name": "Confirm Email Sent",
      "type": "n8n-nodes-base.telegram",
      "position": [
        4960,
        -16
      ],
      "parameters": {
        "text": "=\u2705 *PROPOSAL SENT SUCCESSFULLY*\n\n*To:* {{ $('Prepare Email Data').item.json.final_client_name }} ({{ $('Prepare Email Data').item.json.final_client_email }})\n*Subject:* {{ $('Prepare Email Data').item.json.final_proposal_title }}\n\nThe proposal has been emailed to the client with the PDF attached.\n\n\ud83d\udcc4 [View Doc](https://docs.google.com/document/d/{{ $('Prepare Email Data').item.json.doc_id }})",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "node-22",
      "name": "Notify Proposal Rejected",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3616,
        192
      ],
      "parameters": {
        "text": "=\u274c *PROPOSAL REJECTED*\n\n*Client:* {{ $('Prepare Proposal Data').item.json.CLIENT_NAME }}\n*Reason:* You chose to reject this proposal.\n\nThe proposal doc is still available if you want to edit and resend manually:\n\ud83d\udcc4 [View Doc](https://docs.google.com/document/d/{{ $('Copy Proposal Template').item.json.id }})",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "node-23",
      "name": "Notify No Proposal Needed",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1536,
        288
      ],
      "parameters": {
        "text": "=\u2139\ufe0f *NO PROPOSAL NEEDED*\n\n*Meeting:* {{ $('Get Full Transcript').item.json.data?.transcript?.title || 'Unknown' }}\n*Reason:* {{ $json.reason }}\n\nNo action required.",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "node-24",
      "name": "Notify Transcript Error",
      "type": "n8n-nodes-base.telegram",
      "position": [
        960,
        384
      ],
      "parameters": {
        "text": "=\u26a0\ufe0f *TRANSCRIPT FETCH FAILED*\n\nFireflies webhook received but the transcript could not be retrieved.\n\nPayload received:\n```\n{{ JSON.stringify($('When Transcript Ready').item.json.body, null, 2).substring(0, 500) }}\n```\n\nPlease check the Fireflies API key and transcript ID.",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "sticky-main",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -688,
        -288
      ],
      "parameters": {
        "color": "#646B0B",
        "width": 620,
        "height": 816,
        "content": "## Fireflies Transcript to Auto-Proposal\n\nListens for Fireflies transcript webhooks, qualifies the call with AI, drafts a proposal, fills a Google Doc template, converts to PDF, and sends it via Gmail after you approve in Telegram.\n\n### How it works\n1. Fireflies webhook triggers when a meeting transcript is ready\n2. Fetches the full transcript via GraphQL API\n3. AI classifies the call and extracts client details, pain points, and scope\n4. If a proposal is needed, AI generates structured content for your template\n5. Google Doc template is copied and populated, then exported as PDF\n6. Telegram sends you a summary with Approve/Reject buttons\n7. On approval, the PDF is emailed to the client via Gmail\n\n### Setup\n- [ ] Add your Fireflies API key (HTTP Header Auth credential) and configure the webhook in Fireflies Settings > Developer > Webhooks\n- [ ] Connect your OpenAI API key to both AI nodes\n- [ ] Create a Google Doc template with placeholders: {{CLIENT_NAME}}, {{CLIENT_COMPANY}}, {{MEETING_DATE}}, {{MEETING_RECAP}}, {{UNDERSTANDING_OF_NEEDS}}, {{PROPOSED_SOLUTION}}, {{DELIVERABLES}}, {{TIMELINE}}, {{INVESTMENT}}, {{NEXT_STEPS}}\n- [ ] Set the Doc ID and Drive folder ID in the Google Drive nodes\n- [ ] Connect Gmail OAuth2 credential\n- [ ] Set your Telegram bot token and chat ID in all Telegram nodes\n\n### Customization\n- Edit the AI Qualify prompt to match your sales call criteria\n- Edit the AI Draft prompt to match your brand voice and proposal structure\n- Swap Telegram for Slack if preferred"
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-intake",
      "name": "Sticky Note - Transcript Intake",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -32
      ],
      "parameters": {
        "color": 4,
        "width": 844,
        "height": 560,
        "content": "**Transcript Intake**\nReceives Fireflies webhook, responds 200 OK, fetches full transcript via GraphQL, and validates the response."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-qualify",
      "name": "Sticky Note - AI Qualification",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        800,
        -32
      ],
      "parameters": {
        "color": 5,
        "width": 616,
        "height": 560,
        "content": "**AI Qualification**\nGPT-4o classifies the call type and extracts client details. Non-proposal meetings get a Telegram notification."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-draft",
      "name": "Sticky Note - Proposal Draft",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1424,
        -32
      ],
      "parameters": {
        "color": 6,
        "width": 1452,
        "height": 560,
        "content": "**Proposal Drafting & Document Generation**\nAI generates structured proposal content, populates a Google Doc template copy, exports as PDF, and saves to Drive."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-approval",
      "name": "Sticky Note - Approval Flow",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2880,
        -128
      ],
      "parameters": {
        "color": 2,
        "width": 948,
        "height": 560,
        "content": "**Telegram Approval**\nSends a summary with Approve/Reject buttons. Pauses until you respond. Prompts for client email if missing."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-delivery",
      "name": "Sticky Note - Email Delivery",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3840,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 1332,
        "height": 560,
        "content": "**Email Delivery**\nDownloads the PDF from Drive, emails it to the client via Gmail, and confirms delivery in Telegram."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-warning",
      "name": "Sticky Note - Warning",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2016,
        288
      ],
      "parameters": {
        "color": 3,
        "width": 676,
        "height": 220,
        "content": "**Google Doc Template Required**\nThis workflow will fail without a template. Create a Google Doc with the following placeholders  {{CLIENT_NAME}}, {{CLIENT_COMPANY}}, {{MEETING_DATE}}, {{MEETING_RECAP}}, {{UNDERSTANDING_OF_NEEDS}}, {{PROPOSED_SOLUTION}}, {{DELIVERABLES}}, {{TIMELINE}}, {{INVESTMENT}}, {{NEXT_STEPS}}, then paste the Doc ID into the Copy Proposal Template node."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "timezone": "UTC",
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false,
    "executionOrder": "v1",
    "executionTimeout": 3600,
    "saveManualExecutions": true,
    "saveExecutionProgress": true,
    "saveDataErrorExecution": "all",
    "saveDataSuccessExecution": "all"
  },
  "versionId": "341dc4e5-4a30-491c-839d-b399e5e2055e",
  "connections": {
    "If Approved": {
      "main": [
        [
          {
            "node": "If Client Email Exists",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify Proposal Rejected",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond 200 OK": {
      "main": [
        [
          {
            "node": "Get Full Transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Export Doc as PDF": {
      "main": [
        [
          {
            "node": "Save PDF to Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save PDF to Drive": {
      "main": [
        [
          {
            "node": "Send Approval Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Approval": {
      "main": [
        [
          {
            "node": "If Approved",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Proposal Needed": {
      "main": [
        [
          {
            "node": "Generate Proposal Content",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify No Proposal Needed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Email Data": {
      "main": [
        [
          {
            "node": "Download PDF from Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Full Transcript": {
      "main": [
        [
          {
            "node": "If Transcript Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Proposal Email": {
      "main": [
        [
          {
            "node": "Confirm Email Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ask for Client Email": {
      "main": [
        [
          {
            "node": "Wait for Email Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Transcript Exists": {
      "main": [
        [
          {
            "node": "Classify Meeting Type",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify Transcript Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Email Reply": {
      "main": [
        [
          {
            "node": "Prepare Email Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Meeting Type": {
      "main": [
        [
          {
            "node": "If Proposal Needed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Proposal Data": {
      "main": [
        [
          {
            "node": "Copy Proposal Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Approval Request": {
      "main": [
        [
          {
            "node": "Wait for Approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Transcript Ready": {
      "main": [
        [
          {
            "node": "Respond 200 OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Copy Proposal Template": {
      "main": [
        [
          {
            "node": "Fill Template Placeholders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Client Email Exists": {
      "main": [
        [
          {
            "node": "Prepare Email Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Ask for Client Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download PDF from Drive": {
      "main": [
        [
          {
            "node": "Send Proposal Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Proposal Content": {
      "main": [
        [
          {
            "node": "Prepare Proposal Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fill Template Placeholders": {
      "main": [
        [
          {
            "node": "Export Doc as PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Listens for completed Fireflies transcripts, qualifies whether a proposal is needed using OpenAI, drafts structured proposal content, populates a Google Doc template, converts to PDF, and sends it to the client via Gmail after you approve it in Telegram.

Source: https://n8n.io/workflows/14717/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Streamlit Logibot. Uses notion, ollamaChatModel, lmChatOllama, googleDrive. Event-driven trigger; 29 nodes.

Notion, Ollama Chat Model, Ollama Chat +5
AI & RAG

💥 Automate YouTube thumbnail creation from video links -vide. Uses telegramTrigger, httpRequest, googleDrive, gmail. Event-driven trigger; 25 nodes.

Telegram Trigger, HTTP Request, Google Drive +6
AI & RAG

💥 Automate YouTube thumbnail creation from video links -vide. Uses telegramTrigger, httpRequest, googleDrive, gmail. Event-driven trigger; 25 nodes.

Telegram Trigger, HTTP Request, Google Drive +6
AI & RAG

This system meticulously guides each lead through a fully automated journey, from initial contact to a personalized follow-up and CRM integration.

OpenAI, @Elevenlabs/N8N Nodes Elevenlabs, Google Drive +4
AI & RAG

Stop applying manually. This workflow acts as your personal AI recruiter, automating the end-to-end process of finding high-quality jobs, tailoring your resume, and preparing personalized outreach ema

Google Docs, HTTP Request, OpenAI +2