AutomationFlowsAI & RAG › Generate AI Sales Proposals with Gemini and Google Docs

Generate AI Sales Proposals with Gemini and Google Docs

ByAI Sales Agent HQ @daniellopezscoot on n8n.io

Generate professional sales proposals from a simple form—AI writes the content, you deliver the document.

Event trigger★★★★☆ complexityAI-powered12 nodesForm TriggerAgentGoogle Gemini ChatGoogle DriveGoogle Docs
AI & RAG Trigger: Event Nodes: 12 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Agent → Form Trigger 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": "WNMNYGtBnhK3XivgdCN0w",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Generate sales proposals with Gemini and Google Docs",
  "tags": [
    {
      "id": "K6D3K6nP6k9TByzr",
      "name": "sales-automation",
      "createdAt": "2026-01-14T17:39:47.009Z",
      "updatedAt": "2026-01-14T17:39:47.009Z"
    },
    {
      "id": "NCFzdO7mRAguwdoQ",
      "name": "proposal-generation",
      "createdAt": "2026-01-21T20:39:12.676Z",
      "updatedAt": "2026-01-21T20:39:12.676Z"
    },
    {
      "id": "VoJMSzkknWaPzhGO",
      "name": "google-docs",
      "createdAt": "2026-01-21T20:39:12.679Z",
      "updatedAt": "2026-01-21T20:39:12.679Z"
    }
  ],
  "nodes": [
    {
      "id": "95aec752-5f78-481d-b7df-11097d6521c5",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1920,
        448
      ],
      "parameters": {
        "color": 5,
        "width": 380,
        "height": 816,
        "content": "## How it works\n\nThis workflow generates professional sales proposals from a simple form:\n\n1. **Form** - Sales rep submits client details, pain points, and pricing\n2. **Calculate** - Computes ROI, savings, and break-even metrics\n3. **Generate** - Gemini AI writes executive summary, challenges, solution strategy, and team bios\n4. **Create** - Copies your Google Doc template and populates all placeholders\n\nThe AI tailors content to the client's industry and pain points while incorporating your calculated financial metrics.\n\n## Setup steps\n\n1. **Google Doc template** - Create a doc with placeholders: `{{client_name}}`, `{{executive_summary}}`, `{{key_challenges}}`, `{{solution_strategy}}`, `{{team_bios}}`, `{{formatted_roi}}`, `{{formatted_net_savings}}`, `{{formatted_break_even}}`, `{{next_steps}}`, `{{date}}`\n2. **Credentials** - Connect Google Drive, Google Docs, and Gemini API\n3. **Configure Copy node** - Point to your template document\n4. **Customize AI** - Edit the system message in \"Generate proposal content\" to match your company's tone\n5. **Test** - Submit the form and check the generated proposal"
      },
      "typeVersion": 1
    },
    {
      "id": "9a99fd38-b5fe-45e8-9f9c-f9318bc3b3c0",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2400,
        608
      ],
      "parameters": {
        "color": 7,
        "width": 280,
        "height": 96,
        "content": "**Data preparation**\nForm collects client info. Code node calculates ROI, savings, and break-even from financials."
      },
      "typeVersion": 1
    },
    {
      "id": "5b84d41d-8a9a-402a-8eef-a3bb0628fc86",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2816,
        608
      ],
      "parameters": {
        "color": 7,
        "width": 280,
        "height": 96,
        "content": "**AI generation**\nGemini writes proposal sections based on pain points and financials. Parser extracts JSON fields."
      },
      "typeVersion": 1
    },
    {
      "id": "cd31ccaa-8356-4b3a-b266-e5ead83fef69",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3376,
        608
      ],
      "parameters": {
        "color": 7,
        "width": 300,
        "height": 96,
        "content": "**Document creation**\nCopies template, formats bullet points, and replaces all placeholders with generated content."
      },
      "typeVersion": 1
    },
    {
      "id": "49b28a3b-13e6-4e01-9453-6144be48c82d",
      "name": "Receive proposal details",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        2400,
        752
      ],
      "parameters": {
        "options": {},
        "formTitle": "Proposal Generation Form",
        "formFields": {
          "values": [
            {
              "fieldName": "user_company_name",
              "fieldLabel": "Your Company Name"
            },
            {
              "fieldName": "team_members_input",
              "fieldType": "textarea",
              "fieldLabel": "Team Members & Roles",
              "placeholder": "ane Doe (Lead Engineer), John Smith (Project Manager)"
            },
            {
              "fieldName": "client_name",
              "fieldLabel": "Client Name",
              "placeholder": "For the cover page and headers.",
              "requiredField": true
            },
            {
              "fieldName": "client_industry",
              "fieldLabel": "Client Industry",
              "placeholder": "Helps the AI customize the tone (e.g., Medical vs. Construction).",
              "requiredField": true
            },
            {
              "fieldName": "key_pain_points",
              "fieldType": "textarea",
              "fieldLabel": "Key Pain Points",
              "placeholder": "The raw notes the AI will turn into \"Key Challenges.\"",
              "requiredField": true
            },
            {
              "fieldName": "current_annual_spend",
              "fieldType": "number",
              "fieldLabel": "Current Annual Spend ($)",
              "placeholder": "Crucial for the ROI Logic (e.g., \"50000\").",
              "requiredField": true
            },
            {
              "fieldName": "offer_type",
              "fieldType": "dropdown",
              "fieldLabel": "Offer Type",
              "defaultValue": "Selects which \"Company Context\" to load (e.g., \"SEO Retainer\" vs. \"Web Dev\").",
              "fieldOptions": {
                "values": [
                  {
                    "option": "SEO Retainer"
                  },
                  {
                    "option": "Web Dev"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldName": "proposed_solution_cost",
              "fieldType": "number",
              "fieldLabel": "Proposed Solution Cost ($)",
              "placeholder": "Crucial for the ROI Logic (e.g., \"12000\").",
              "requiredField": true
            },
            {
              "fieldName": "project_start_date",
              "fieldType": "date",
              "fieldLabel": "Project Start Date",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Fill out these fields for your client to generate a proposal."
      },
      "typeVersion": 2.4
    },
    {
      "id": "a2afdd6b-a539-44a5-8740-cfb714337059",
      "name": "Calculate ROI metrics",
      "type": "n8n-nodes-base.code",
      "position": [
        2608,
        752
      ],
      "parameters": {
        "jsCode": "// 1. Get the data\nconst formData = items[0].json;\n\n// 2. Helper function to clean inputs\nfunction cleanNumber(value) {\n  if (typeof value === 'number') return value;\n  if (!value) return 0;\n  return parseFloat(value.toString().replace(/[^0-9.-]+/g,\"\"));\n}\n\n// 3. Extract and Clean Variables\nconst currentSpend = cleanNumber(formData.current_annual_spend || 0);\nconst solutionCost = cleanNumber(formData.proposed_solution_cost || 0);\nconst clientName = formData.client_name || \"Valued Client\";\nconst painPoints = formData.key_pain_points || \"\";\n\n// --- CONFIGURATION ---\nconst efficiencyAssumption = 1.0; \n// ---------------------\n\n// 4. Perform Calculations\nconst grossSavings = currentSpend * efficiencyAssumption; \nconst netSavings = grossSavings - solutionCost;\nlet roiPercent = 0;\nlet breakEvenMonths = 0;\n\nif (solutionCost > 0) {\n  roiPercent = (netSavings / solutionCost) * 100;\n  breakEvenMonths = solutionCost / (grossSavings / 12);\n}\n\n// 5. Format for Humans\nconst currencyFormatter = new Intl.NumberFormat('en-US', {\n  style: 'currency',\n  currency: 'USD',\n  maximumFractionDigits: 0\n});\n\nreturn {\n  json: {\n    client_name: clientName,\n    pain_points: painPoints,\n    \n    // Financials\n    raw_savings: netSavings,\n    raw_roi: roiPercent,\n    \n    // Formatted Text\n    formatted_current_spend: currencyFormatter.format(currentSpend),\n    formatted_solution_cost: currencyFormatter.format(solutionCost),\n    formatted_net_savings: currencyFormatter.format(netSavings),\n    formatted_roi: Math.round(roiPercent) + \"%\",\n    formatted_break_even: breakEvenMonths.toFixed(1) + \" Months\",\n    \n    // AI Context\n    ai_financial_context: `By implementing this solution, ${clientName} is projected to see a ${Math.round(roiPercent)}% ROI, recovering the initial investment in approximately ${breakEvenMonths.toFixed(1)} months.`\n  }\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "a1eac7e9-acf9-497b-88d8-670b643deded",
      "name": "Generate proposal content",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2816,
        752
      ],
      "parameters": {
        "text": "=Here are the details for the new proposal:\n\nCLIENT: {{ $('Receive proposal details').item.json.client_name }}\nMY COMPANY: {{ $('Receive proposal details').first().json.user_company_name }}\nMY TEAM MEMBERS (Raw List): {{ $('Receive proposal details').first().json.team_members_input }}\n\nPAIN POINTS: {{ $('Receive proposal details').item.json.key_pain_points }}\n\nFINANCIAL DATA:\n- ROI: {{ $('Calculate ROI metrics').first().json.formatted_roi }}\n- Annual Savings: {{ $('Calculate ROI metrics').first().json.formatted_net_savings }}\n- Break Even: {{ $('Calculate ROI metrics').first().json.formatted_break_even }}\n\nFINANCIAL NARRATIVE:\n{{ $('Calculate ROI metrics').first().json.ai_financial_context }}\n\nPlease generate the JSON proposal now.",
        "options": {
          "systemMessage": "You are an expert Enterprise Sales Engineer. Your goal is to write a winning business proposal based on the client data provided.\n\n### YOUR WRITING RULES:\n1. Tone: Professional, confident, and value-driven.\n2. Financials: Always tie the solution back to the financial savings provided.\n3. Team Section: You must write the \"team_bio_section\" as a complete narrative text block (not a JSON list).\n   - Start with a warm introductory sentence (e.g., \"We have assembled a team of experts dedicated to [Client Name]'s success...\").\n   - Then, list the team members provided in the \"MY TEAM MEMBERS\" input using a dash (-) for each new line. Include their Name, Title, and a brief 1-sentence bio.\n   - End with a closing sentence about their commitment to the project (e.g., \"This team will be your dedicated support...\").\n   - DO NOT invent a fake company name. Use the \"MY COMPANY\" name provided.\n\n### OUTPUT FORMAT:\nOutput ONLY a valid JSON object with these keys:\n{\n  \"short_outcome_phrase\": \"A 2-5 word strategic goal based on their pain points.\",\n  \"executive_summary\": \"A 3-4 sentence hook summarizing the problem and value.\",\n  \"key_challenges_bullet_points\": \"A list of the 3 biggest pain points.\",\n  \"solution_strategy\": \"A 2 paragraph roadmap of the solution.\",\n  \"team_bio_section\": \"A single text string containing the Intro, the List (with line breaks), and the Outro.\",\n  \"call_to_action\": \"A closing sentence urging them to sign.\"\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "317d80a5-dd25-47a2-a385-43a424014653",
      "name": "Gemini 1.5 Flash",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        2800,
        960
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7aea949b-296c-408f-8c38-dd419a53e182",
      "name": "Parse AI response",
      "type": "n8n-nodes-base.code",
      "position": [
        3168,
        752
      ],
      "parameters": {
        "jsCode": "// 1. Get the raw text output from the AI Agent\nconst rawOutput = $('Generate proposal content').first().json.output;\n\ntry {\n  // 2. Locate the JSON object within the text\n  const jsonMatch = rawOutput.match(/\\{[\\s\\S]*\\}/);\n\n  if (!jsonMatch) {\n    throw new Error(\"No JSON object found in AI response\");\n  }\n\n  // 3. Parse the cleaned string into a real Object\n  const cleanJson = JSON.parse(jsonMatch[0]);\n\n  // 4. Return the clean data\n  return {\n    json: cleanJson\n  };\n\n} catch (error) {\n  return {\n    json: {\n      error: \"Failed to parse JSON\",\n      message: error.message,\n      raw_ai_response: rawOutput\n    }\n  };\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "7965738d-fdd8-4877-bc93-c32bb1287367",
      "name": "Copy proposal template",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3376,
        752
      ],
      "parameters": {
        "name": "={{ $('Receive proposal details').item.json.client_name }} Proposal",
        "fileId": {
          "__rl": true,
          "mode": "list",
          "value": "1SCu_o75YfEPgTaP3JgaLYncZ8hz--AQ_wNPpJq4qrFE",
          "cachedResultUrl": "https://docs.google.com/document/d/1SCu_o75YfEPgTaP3JgaLYncZ8hz--AQ_wNPpJq4qrFE/edit?usp=drivesdk",
          "cachedResultName": "Proposal Template Master"
        },
        "options": {},
        "operation": "copy"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "dca9cd9e-4dc8-47e6-8138-a93d9a925f16",
      "name": "Format bullet points",
      "type": "n8n-nodes-base.code",
      "position": [
        3584,
        752
      ],
      "parameters": {
        "jsCode": "// 1. Get the raw data\nconst aiData = $('Parse AI response').first().json;\n\n// 2. Helper function\nfunction formatAsBullets(input) {\n  if (Array.isArray(input)) {\n    const cleanItems = input.map(item => item.replace(/^[-\u2022*]\\s*/, '').trim());\n    return \"\u2022 \" + cleanItems.join(\"\\n\u2022 \");\n  }\n  return input || \"\"; \n}\n\n// 3. Format fields\nconst challengesClean = formatAsBullets(aiData.key_challenges_bullet_points);\nconst biosClean = formatAsBullets(aiData.team_bio_section);\n\nreturn {\n  json: {\n    ready_challenges: challengesClean,\n    ready_bios: biosClean\n  }\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "c46fc679-3e25-4459-81a5-cb376acaf2ca",
      "name": "Populate proposal document",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        3792,
        752
      ],
      "parameters": {
        "actionsUi": {
          "actionFields": [
            {
              "text": "{{client_name}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Receive proposal details').item.json.client_name }}"
            },
            {
              "text": "{{user_company_name}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Receive proposal details').item.json.user_company_name }}"
            },
            {
              "text": "{{dynamic_title}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Receive proposal details').item.json.client_name }}+ {{ $('Receive proposal details').first().json['user_company_name'] }}: {{ $('Parse AI response').first().json['short_outcome_phrase'] }}"
            },
            {
              "text": "{{formatted_roi}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_roi }}"
            },
            {
              "text": "{{executive_summary}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Parse AI response').item.json.executive_summary }}"
            },
            {
              "text": "{{key_challenges}}",
              "action": "replaceAll",
              "replaceText": "={{ $json.ready_challenges }}"
            },
            {
              "text": "{{solution_strategy}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Parse AI response').item.json.solution_strategy }}"
            },
            {
              "text": "{{team_bios}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Parse AI response').item.json.team_bio_section }}"
            },
            {
              "text": "{{next_steps}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Parse AI response').item.json.call_to_action }}"
            },
            {
              "text": "{{formatted_net_savings}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_net_savings }}"
            },
            {
              "text": "{{formatted_solution_cost}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_solution_cost }}"
            },
            {
              "text": "{{formatted_break_even}}",
              "action": "replaceAll",
              "replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_break_even }}"
            },
            {
              "text": "{{date}}",
              "action": "replaceAll",
              "replaceText": "={{ $now.toFormat('MMMM dd, yyyy') }}"
            }
          ]
        },
        "operation": "update",
        "documentURL": "={{ $('Copy proposal template').item.json.id }}"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    }
  ],
  "active": true,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "d7076d3a-3856-4857-b4fd-96125a4353c3",
  "connections": {
    "Gemini 1.5 Flash": {
      "ai_languageModel": [
        [
          {
            "node": "Generate proposal content",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI response": {
      "main": [
        [
          {
            "node": "Copy proposal template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format bullet points": {
      "main": [
        [
          {
            "node": "Populate proposal document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate ROI metrics": {
      "main": [
        [
          {
            "node": "Generate proposal content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Copy proposal template": {
      "main": [
        [
          {
            "node": "Format bullet points",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive proposal details": {
      "main": [
        [
          {
            "node": "Calculate ROI metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate proposal content": {
      "main": [
        [
          {
            "node": "Parse AI response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

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.

Pro

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

About this workflow

Generate professional sales proposals from a simple form—AI writes the content, you deliver the document.

Source: https://n8n.io/workflows/12715/ — 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

This n8n template automatically crawls technical documentation websites, scrapes their content, and converts it into clean, structured, developer-friendly documentation. Each page is organized into fo

Google Drive, N8N Nodes Olostep, Information Extractor +3
AI & RAG

This n8n template automates complaint mining from unstructured text sources and turns raw user feedback into clear, actionable insights. It uses AI to identify recurring complaints, pain points, and t

Output Parser Structured, Chain Llm, Google Gemini Chat +5
AI & RAG

Streamline your recruitment process with AI-powered resume analysis that goes beyond keyword matching.

Form Trigger, Google Drive, Google Gemini Chat +7
AI & RAG

This workflow automates batch video publishing prep from a Google Drive folder with AI-generated, platform-specific copy and a simple approval queue in Google Sheets. Perfect for Agencies, content cre

Form Trigger, Google Drive, Google Gemini +5
AI & RAG

This workflow automates the entire UX research planning process — from gathering context to delivering a ready-to-share Google Doc report. Built for UX researchers and designers, it combines AI-powere

Form Trigger, Google Gemini Chat, Agent +3