{
  "id": "TyRa6OQry8lTHZFw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Generate and send personalized client proposals by client type via email with AI",
  "tags": [],
  "nodes": [
    {
      "id": "906e7e49-1fa0-4d21-9bfe-4f258e72e536",
      "name": "Sticky Note - Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        208
      ],
      "parameters": {
        "width": 880,
        "height": 820,
        "content": "## Generate and send personalized client proposals by client type via email with AI\n\n### Who's it for\n- Sales teams sending 10+ proposals per week who need consistent, branded output\n- Freelancers and agencies automating their proposal pipeline from a CRM or web form\n- Business development teams wanting AI-written proposals without manual copy work\n- Service businesses with multiple client tiers needing different pricing and tone per segment\n\n### How it works\n1. Client submits a request via webhook POST from a CRM, contact form, or API\n2. Alternatively, a scheduler polls a form submission queue every hour\n3. All field name variants are normalised into a consistent schema\n4. JS validates required fields and classifies the budget into a tier (starter / growth / enterprise / enterprise+)\n5. Invalid requests receive a polite error email with the missing fields listed\n6. A Switch node routes valid requests to one of five templates based on client type: startup, enterprise, agency, nonprofit, or standard\n7. Conditional pricing logic applies base prices, line items per service, and client-type discounts\n8. AI generates a 7-section personalized proposal using the client data, pricing, and template context\n9. A JS node formats the proposal into a branded HTML email with an investment breakdown table\n10. The proposal is sent to the client via SendGrid, logged to Google Sheets, and a Slack alert is sent to the team\n11. A 200 success response is returned to the webhook caller\n\n### How to customize\n- Add new client types by creating a new Set node with template fields and adding a condition to the Switch node\n- Adjust pricing tiers and base rates in `JS - Conditional Pricing Logic` under the `basePrices` object\n- Change discount rules per client type in the same node \u2014 currently nonprofits get 20% and early-stage startups get 10%\n- Modify the 7-section proposal structure by editing the section headings in the AI prompt inside `AI - Generate Proposal Copy`\n- Add a PDF generation step after `JS - Format Proposal Document` using an HTML-to-PDF service like Puppeteer or WeasyPrint\n- Swap SendGrid for the native Gmail node if you prefer Google Workspace delivery\n- Extend the Google Sheet columns to track proposal acceptance status and follow-up dates"
      },
      "typeVersion": 1
    },
    {
      "id": "7741b45d-f9f2-4065-a8f2-02e0e50782f3",
      "name": "Sticky Note - Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        432
      ],
      "parameters": {
        "color": 4,
        "width": 764,
        "height": 500,
        "content": "## 1. Trigger & Intake\n\nAccepts POST from any CRM, form, or API.\nAlso polls hourly as a fallback.\nNormalizes all field name variants."
      },
      "typeVersion": 1
    },
    {
      "id": "7afff03e-dc30-4181-b123-e6102b56c965",
      "name": "Sticky Note - Validate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1808,
        384
      ],
      "parameters": {
        "color": 4,
        "width": 764,
        "height": 1124,
        "content": "## 2. Validate & Classify\n\nChecks required fields, converts budget to numeric, assigns budgetTier. Invalid requests branch to a polite error email."
      },
      "typeVersion": 1
    },
    {
      "id": "0c7a8723-aac6-44a8-b599-78a28382dde6",
      "name": "Sticky Note - AI Generation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2656,
        448
      ],
      "parameters": {
        "color": 4,
        "width": 708,
        "height": 620,
        "content": "## 3. Template Selection & AI Generation\n\nSwitch routes by clientType to one of 5 templates. Pricing logic applies discounts and builds line items. AI generates a 7-section personalized proposal."
      },
      "typeVersion": 1
    },
    {
      "id": "ea7a829e-9a1f-49cf-a9f2-784fa83efe00",
      "name": "Sticky Note - Deliver",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3472,
        336
      ],
      "parameters": {
        "color": 4,
        "width": 1196,
        "height": 796,
        "content": "## 4. Deliver & Track\n\nFormats branded HTML proposal, sends to client via SendGrid, logs to Google Sheets, notifies team on Slack, and returns a webhook response."
      },
      "typeVersion": 1
    },
    {
      "id": "0e113acb-cf08-4002-a087-e507bfa880e7",
      "name": "Webhook - New Proposal Request",
      "type": "n8n-nodes-base.webhook",
      "position": [
        1056,
        592
      ],
      "parameters": {
        "path": "proposal-request",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 1.1
    },
    {
      "id": "1b00d593-ad8e-4532-80f9-debe72c2a94b",
      "name": "Poll - Hourly Form Submissions",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1056,
        768
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 * * * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "8a613abb-ce48-46fc-80b7-3bcd398b190b",
      "name": "Normalize Client Data",
      "type": "n8n-nodes-base.set",
      "position": [
        1248,
        688
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f001",
              "name": "clientName",
              "type": "string",
              "value": "={{ $json.clientName || $json.body?.clientName || $json.body?.client_name || '' }}"
            },
            {
              "id": "f002",
              "name": "clientEmail",
              "type": "string",
              "value": "={{ $json.clientEmail || $json.body?.clientEmail || $json.body?.client_email || '' }}"
            },
            {
              "id": "f003",
              "name": "companyName",
              "type": "string",
              "value": "={{ $json.companyName || $json.body?.companyName || $json.body?.company || 'N/A' }}"
            },
            {
              "id": "f004",
              "name": "projectScope",
              "type": "string",
              "value": "={{ $json.projectScope || $json.body?.projectScope || $json.body?.scope || '' }}"
            },
            {
              "id": "f005",
              "name": "servicesNeeded",
              "type": "string",
              "value": "={{ $json.servicesNeeded || $json.body?.servicesNeeded || $json.body?.services || '' }}"
            },
            {
              "id": "f006",
              "name": "budget",
              "type": "string",
              "value": "={{ $json.budget || $json.body?.budget || '0' }}"
            },
            {
              "id": "f007",
              "name": "timeline",
              "type": "string",
              "value": "={{ $json.timeline || $json.body?.timeline || '30 days' }}"
            },
            {
              "id": "f008",
              "name": "clientType",
              "type": "string",
              "value": "={{ ($json.clientType || $json.body?.clientType || $json.body?.client_type || 'standard').toLowerCase() }}"
            },
            {
              "id": "f009",
              "name": "industry",
              "type": "string",
              "value": "={{ $json.industry || $json.body?.industry || 'General' }}"
            },
            {
              "id": "f010",
              "name": "submittedAt",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            },
            {
              "id": "f011",
              "name": "requestId",
              "type": "string",
              "value": "={{ 'PRO-' + Date.now().toString().slice(-8) }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4eeb75f1-0fd3-418e-a976-de6160c70973",
      "name": "JS - Validate and Classify",
      "type": "n8n-nodes-base.code",
      "position": [
        1584,
        688
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json;\nconst errors = [];\nconst required = ['clientName', 'clientEmail', 'projectScope', 'budget'];\nfor (const field of required) {\n  if (!item[field] || item[field].toString().trim() === '') {\n    errors.push('Missing required field: ' + field);\n  }\n}\nconst budgetRaw = String(item.budget || '0').replace(/[,$\\s]/g, '');\nconst budgetNumeric = parseFloat(budgetRaw) || 0;\nlet budgetTier = 'starter';\nif (budgetNumeric >= 50000) budgetTier = 'enterprise_plus';\nelse if (budgetNumeric >= 10000) budgetTier = 'enterprise';\nelse if (budgetNumeric >= 1000) budgetTier = 'growth';\nreturn {\n  json: {\n    ...item,\n    budgetNumeric,\n    budgetTier,\n    isValid: errors.length === 0,\n    validationErrors: errors\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "f998ca29-463a-4a0b-a8d2-1feb2aa828b9",
      "name": "Filter - Valid Requests Only",
      "type": "n8n-nodes-base.filter",
      "position": [
        1872,
        688
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-valid-001",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.isValid }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4ce22f88-8855-45c0-91c9-8a756741be61",
      "name": "Send Validation Error Notice",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2176,
        1056
      ],
      "parameters": {
        "url": "https://api.sendgrid.com/v3/mail/send",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"personalizations\": [{\"to\": [{\"email\": \"{{ $json.clientEmail }}\"}]}],\n  \"from\": {\"email\": \"proposals@yourcompany.com\", \"name\": \"Your Company\"},\n  \"subject\": \"Missing info on your proposal request\",\n  \"content\": [{\"type\": \"text/plain\", \"value\": \"Hi {{ $json.clientName }},\\n\\nWe received your request but some required information was missing: {{ $json.validationErrors.join(', ') }}\\n\\nPlease resubmit with complete details.\\n\\nBest regards,\\nThe Proposals Team\"}]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "1234e213-cf8c-4c6f-9031-49e12cfdb6c7",
      "name": "Switch - Client Type Router",
      "type": "n8n-nodes-base.switch",
      "position": [
        2080,
        672
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "startup",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "sw-cond-001",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.clientType }}",
                    "rightValue": "startup"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "enterprise",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "sw-cond-002",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.clientType }}",
                    "rightValue": "enterprise"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "agency",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "sw-cond-003",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.clientType }}",
                    "rightValue": "agency"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "nonprofit",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "sw-cond-004",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.clientType }}",
                    "rightValue": "nonprofit"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "8cb0449c-32bf-47bc-9458-9a62add27298",
      "name": "Template - Startup",
      "type": "n8n-nodes-base.set",
      "position": [
        2368,
        528
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "t1f1",
              "name": "templateName",
              "type": "string",
              "value": "Startup Growth Package"
            },
            {
              "id": "t1f2",
              "name": "templateId",
              "type": "string",
              "value": "TPL-STARTUP-001"
            },
            {
              "id": "t1f3",
              "name": "headerColor",
              "type": "string",
              "value": "#6C63FF"
            },
            {
              "id": "t1f4",
              "name": "defaultPaymentTerms",
              "type": "string",
              "value": "50% upfront, 50% on delivery"
            },
            {
              "id": "t1f5",
              "name": "defaultWarranty",
              "type": "string",
              "value": "30-day bug-fix warranty included"
            },
            {
              "id": "t1f6",
              "name": "templateFocus",
              "type": "string",
              "value": "agile delivery, lean MVP, fast time-to-market"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "02a62613-2b75-4a71-afbc-5c66202872de",
      "name": "Template - Enterprise",
      "type": "n8n-nodes-base.set",
      "position": [
        2384,
        704
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "t2f1",
              "name": "templateName",
              "type": "string",
              "value": "Enterprise Solutions Package"
            },
            {
              "id": "t2f2",
              "name": "templateId",
              "type": "string",
              "value": "TPL-ENT-001"
            },
            {
              "id": "t2f3",
              "name": "headerColor",
              "type": "string",
              "value": "#1A365D"
            },
            {
              "id": "t2f4",
              "name": "defaultPaymentTerms",
              "type": "string",
              "value": "Net 30, milestone-based billing"
            },
            {
              "id": "t2f5",
              "name": "defaultWarranty",
              "type": "string",
              "value": "90-day SLA with dedicated support"
            },
            {
              "id": "t2f6",
              "name": "templateFocus",
              "type": "string",
              "value": "scalability, security, compliance, enterprise integration"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "c9baed48-0f6a-4bf5-9e7c-32db9addadf1",
      "name": "Template - Agency",
      "type": "n8n-nodes-base.set",
      "position": [
        2384,
        880
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "t3f1",
              "name": "templateName",
              "type": "string",
              "value": "Agency White-Label Package"
            },
            {
              "id": "t3f2",
              "name": "templateId",
              "type": "string",
              "value": "TPL-AGENCY-001"
            },
            {
              "id": "t3f3",
              "name": "headerColor",
              "type": "string",
              "value": "#2D6A4F"
            },
            {
              "id": "t3f4",
              "name": "defaultPaymentTerms",
              "type": "string",
              "value": "Monthly retainer or project-based"
            },
            {
              "id": "t3f5",
              "name": "defaultWarranty",
              "type": "string",
              "value": "Unlimited revisions within project scope"
            },
            {
              "id": "t3f6",
              "name": "templateFocus",
              "type": "string",
              "value": "white-label delivery, reseller margins, quick turnaround"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a51b47c7-955c-4f0a-a62e-c0e9f521e0f9",
      "name": "Template - Nonprofit",
      "type": "n8n-nodes-base.set",
      "position": [
        2384,
        1040
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "t4f1",
              "name": "templateName",
              "type": "string",
              "value": "Nonprofit Impact Package"
            },
            {
              "id": "t4f2",
              "name": "templateId",
              "type": "string",
              "value": "TPL-NPO-001"
            },
            {
              "id": "t4f3",
              "name": "headerColor",
              "type": "string",
              "value": "#E07B39"
            },
            {
              "id": "t4f4",
              "name": "defaultPaymentTerms",
              "type": "string",
              "value": "Grant-cycle aligned billing, flexible terms"
            },
            {
              "id": "t4f5",
              "name": "defaultWarranty",
              "type": "string",
              "value": "60-day support, discounted rate on extensions"
            },
            {
              "id": "t4f6",
              "name": "templateFocus",
              "type": "string",
              "value": "mission-driven value, social impact, cost-efficiency"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "6d6b1581-4c0f-4831-aa4c-0828324de4d6",
      "name": "Template - Standard Default",
      "type": "n8n-nodes-base.set",
      "position": [
        2384,
        1232
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "t5f1",
              "name": "templateName",
              "type": "string",
              "value": "Standard Business Package"
            },
            {
              "id": "t5f2",
              "name": "templateId",
              "type": "string",
              "value": "TPL-STD-001"
            },
            {
              "id": "t5f3",
              "name": "headerColor",
              "type": "string",
              "value": "#334155"
            },
            {
              "id": "t5f4",
              "name": "defaultPaymentTerms",
              "type": "string",
              "value": "50% upfront, 50% on delivery"
            },
            {
              "id": "t5f5",
              "name": "defaultWarranty",
              "type": "string",
              "value": "30-day support included"
            },
            {
              "id": "t5f6",
              "name": "templateFocus",
              "type": "string",
              "value": "reliable delivery, clear milestones, professional quality"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e569f898-3f49-45ec-bbc6-f2a96ef4a198",
      "name": "JS - Conditional Pricing Logic",
      "type": "n8n-nodes-base.code",
      "position": [
        2736,
        688
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json;\nconst tier = item.budgetTier || 'starter';\nconst clientType = (item.clientType || 'standard').toLowerCase();\nconst services = (item.servicesNeeded || '').toLowerCase();\n\nconst basePrices = {\n  starter:         { setup: 500,   monthly: 200,  hourly: 75  },\n  growth:          { setup: 2000,  monthly: 800,  hourly: 100 },\n  enterprise:      { setup: 8000,  monthly: 3000, hourly: 150 },\n  enterprise_plus: { setup: 20000, monthly: 8000, hourly: 200 }\n};\nconst price = basePrices[tier] || basePrices['starter'];\n\nlet discountPct = 0;\nif (clientType === 'nonprofit') discountPct = 20;\nelse if (clientType === 'startup' && (item.budgetNumeric || 0) < 5000) discountPct = 10;\nconst discountLabel = discountPct > 0 ? (discountPct + '% ' + clientType + ' discount applied') : 'No discount';\n\nconst lineItems = [];\nif (services.includes('design') || services.includes('ui') || services.includes('ux')) {\n  lineItems.push({ service: 'UI/UX Design', price: price.hourly * 20 });\n}\nif (services.includes('development') || services.includes('dev') || services.includes('code')) {\n  lineItems.push({ service: 'Software Development', price: price.hourly * 40 });\n}\nif (services.includes('seo') || services.includes('marketing')) {\n  lineItems.push({ service: 'SEO & Digital Marketing', price: price.monthly });\n}\nif (services.includes('consulting') || services.includes('strategy')) {\n  lineItems.push({ service: 'Strategy & Consulting', price: price.hourly * 10 });\n}\nif (services.includes('maintenance') || services.includes('support')) {\n  lineItems.push({ service: 'Ongoing Support & Maintenance', price: price.monthly });\n}\nif (lineItems.length === 0) {\n  lineItems.push({ service: 'Custom Project Delivery', price: price.setup });\n}\n\nconst subtotal = lineItems.reduce(function(sum, l) { return sum + l.price; }, 0);\nconst discountAmount = Math.round(subtotal * (discountPct / 100));\nconst total = subtotal - discountAmount;\n\nreturn {\n  json: {\n    ...item,\n    pricingTier: tier,\n    lineItems: lineItems,\n    subtotal: subtotal,\n    discountPct: discountPct,\n    discountAmount: discountAmount,\n    discountLabel: discountLabel,\n    totalPrice: total,\n    formattedTotal: '$' + total.toLocaleString(),\n    currencyCode: 'USD'\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "1a0aeea8-60a4-4b54-acc1-17c8316fec14",
      "name": "Wait - Rate Limit Buffer",
      "type": "n8n-nodes-base.wait",
      "position": [
        2960,
        688
      ],
      "parameters": {
        "amount": 2
      },
      "typeVersion": 1.1
    },
    {
      "id": "6f0e0885-5311-4b55-80fe-5167cec9fdaa",
      "name": "AI - Generate Proposal Copy",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        3120,
        688
      ],
      "parameters": {
        "text": "=You are an expert business proposal writer. Write a professional, persuasive, and personalized proposal for the client below. It must feel tailored \u2014 not generic.\n\n--- CLIENT ---\nName: {{ $json.clientName }}\nCompany: {{ $json.companyName }}\nIndustry: {{ $json.industry }}\nClient Type: {{ $json.clientType }}\n\n--- PROJECT ---\nScope: {{ $json.projectScope }}\nServices: {{ $json.servicesNeeded }}\nTimeline: {{ $json.timeline }}\nBudget: {{ $json.budget }}\n\n--- PRICING ---\nTotal: {{ $json.formattedTotal }}\nDiscount: {{ $json.discountLabel }}\nPayment Terms: {{ $json.defaultPaymentTerms }}\n\n--- TEMPLATE CONTEXT ---\nFocus: {{ $json.templateFocus }}\nWarranty: {{ $json.defaultWarranty }}\n\nWrite the proposal with these exact section headings:\n1. Executive Summary\n2. Our Understanding of Your Needs\n3. Proposed Solution and Deliverables\n4. Timeline and Milestones\n5. Investment Summary\n6. Why Choose Us\n7. Next Steps\n\nTone: professional but warm. No jargon. Maximum 500 words total.",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 1.6
    },
    {
      "id": "0778cdf9-114d-4f5e-aa37-881db7835a60",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        3216,
        912
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ccff6f9a-50df-47c3-875f-8700002e2592",
      "name": "JS - Format Proposal Document",
      "type": "n8n-nodes-base.code",
      "position": [
        3568,
        688
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json;\nconst proposalText = item.output || item.response || item.text || 'Proposal content unavailable.';\n\nconst lineItemRows = (item.lineItems || []).map(function(l) {\n  return '<tr><td style=\"padding:8px 12px;border-bottom:1px solid #e2e8f0\">' + l.service + '</td><td style=\"padding:8px 12px;border-bottom:1px solid #e2e8f0;text-align:right\">$' + l.price.toLocaleString() + '</td></tr>';\n}).join('');\n\nconst discountRow = item.discountAmount > 0\n  ? '<tr><td style=\"padding:8px 12px;color:#16a34a\">Discount (' + item.discountLabel + ')</td><td style=\"padding:8px 12px;color:#16a34a;text-align:right\">-$' + item.discountAmount.toLocaleString() + '</td></tr>'\n  : '';\n\nconst hColor = item.headerColor || '#334155';\nconst today = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n\nconst htmlProposal = '<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>body{font-family:Segoe UI,Arial,sans-serif;color:#1e293b;margin:0;padding:0;background:#f8fafc}.wrapper{max-width:720px;margin:32px auto;background:#fff;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.08);overflow:hidden}.header{background:' + hColor + ';color:#fff;padding:36px 40px}.header h1{margin:0 0 6px;font-size:26px;font-weight:700}.header p{margin:0;opacity:.85;font-size:15px}.meta{background:#f1f5f9;padding:16px 40px;font-size:13px;color:#64748b}.body{padding:36px 40px;white-space:pre-wrap;line-height:1.8;font-size:15px}.ptable{width:100%;border-collapse:collapse;margin:24px 0;font-size:14px}.ptable th{background:#f1f5f9;padding:10px 12px;text-align:left;font-weight:600;color:#475569}.trow td{font-weight:700;font-size:16px;padding:12px;background:#f8fafc}.footer{background:#f8fafc;padding:20px 40px;font-size:12px;color:#94a3b8;border-top:1px solid #e2e8f0;text-align:center}.cta{text-align:center;margin:32px 0 8px}.cta a{background:' + hColor + ';color:#fff;text-decoration:none;padding:14px 32px;border-radius:8px;font-weight:600;font-size:15px}</style></head><body><div class=\"wrapper\"><div class=\"header\"><h1>Business Proposal</h1><p>Prepared for ' + item.clientName + ' &middot; ' + item.companyName + '</p></div><div class=\"meta\"><strong>Proposal ID:</strong> ' + item.requestId + ' &nbsp;&nbsp; <strong>Date:</strong> ' + today + ' &nbsp;&nbsp; <strong>Template:</strong> ' + item.templateName + ' &nbsp;&nbsp; <strong>Timeline:</strong> ' + item.timeline + '</div><div class=\"body\">' + proposalText + '</div><div style=\"padding:0 40px 24px\"><h3 style=\"color:#475569;font-size:13px;text-transform:uppercase;letter-spacing:.05em\">Investment Breakdown</h3><table class=\"ptable\"><thead><tr><th>Service</th><th style=\"text-align:right\">Price</th></tr></thead><tbody>' + lineItemRows + discountRow + '</tbody><tr class=\"trow\"><td>Total Investment</td><td style=\"text-align:right\">' + item.formattedTotal + '</td></tr></table><p style=\"font-size:13px;color:#64748b\">Payment Terms: ' + item.defaultPaymentTerms + '<br>Warranty: ' + item.defaultWarranty + '</p></div><div class=\"cta\"><a href=\"mailto:user@example.com?subject=Accepting Proposal ' + item.requestId + '\">Accept This Proposal</a></div><div class=\"footer\">This proposal is valid for 14 days. Questions? Reply to this email.<br>&copy; ' + new Date().getFullYear() + ' Your Company Name. All rights reserved.</div></div></body></html>';\n\nreturn {\n  json: {\n    ...item,\n    proposalText: proposalText,\n    htmlProposal: htmlProposal,\n    status: 'Proposal Generated',\n    sentDate: new Date().toISOString().split('T')[0]\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "348cbfd2-c6aa-418a-bb20-34a7a1a95fe8",
      "name": "Wait - Review Buffer",
      "type": "n8n-nodes-base.wait",
      "position": [
        3760,
        688
      ],
      "parameters": {
        "amount": 3
      },
      "typeVersion": 1.1
    },
    {
      "id": "8bd08989-65b9-4902-a82b-864bf0212210",
      "name": "Send Proposal Email",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4032,
        560
      ],
      "parameters": {
        "url": "https://api.sendgrid.com/v3/mail/send",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"personalizations\": [{\"to\": [{\"email\": \"{{ $json.clientEmail }}\", \"name\": \"{{ $json.clientName }}\"}]}],\n  \"from\": {\"email\": \"proposals@yourcompany.com\", \"name\": \"Your Company Proposals\"},\n  \"reply_to\": {\"email\": \"proposals@yourcompany.com\"},\n  \"subject\": \"Your Custom Proposal is Ready - {{ $json.requestId }}\",\n  \"content\": [\n    {\"type\": \"text/plain\", \"value\": \"Hi {{ $json.clientName }},\\n\\nYour proposal is ready.\\n\\nProposal ID: {{ $json.requestId }}\\nTotal Investment: {{ $json.formattedTotal }}\\nTimeline: {{ $json.timeline }}\\n\\nThis proposal is valid for 14 days. To accept, reply to this email.\\n\\nBest regards,\\nYour Company Team\"},\n    {\"type\": \"text/html\", \"value\": \"{{ $json.htmlProposal }}\"}\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "59512372-1ba6-48fb-bcfd-450667b1e248",
      "name": "Log to Google Sheets Tracker",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4048,
        736
      ],
      "parameters": {
        "url": "https://sheets.googleapis.com/v4/spreadsheets/YOUR_SHEET_ID/values/Proposals!A1:append?valueInputOption=USER_ENTERED",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"values\": [[\n    \"{{ $json.requestId }}\",\n    \"{{ $json.sentDate }}\",\n    \"{{ $json.clientName }}\",\n    \"{{ $json.clientEmail }}\",\n    \"{{ $json.companyName }}\",\n    \"{{ $json.clientType }}\",\n    \"{{ $json.industry }}\",\n    \"{{ $json.templateName }}\",\n    \"{{ $json.budgetTier }}\",\n    \"{{ $json.formattedTotal }}\",\n    \"{{ $json.timeline }}\",\n    \"Sent\",\n    \"{{ new Date().toISOString() }}\"\n  ]]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "38b1a722-1245-4452-a954-d8210fb6e61c",
      "name": "Notify Team - Slack",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4048,
        944
      ],
      "parameters": {
        "url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"text\": \"New Proposal Sent\",\n  \"blocks\": [\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \":page_facing_up: *New Proposal Sent*\\n*Client:* {{ $json.clientName }} ({{ $json.companyName }})\\n*ID:* `{{ $json.requestId }}`\\n*Template:* {{ $json.templateName }}\\n*Total:* *{{ $json.formattedTotal }}*\\n*Timeline:* {{ $json.timeline }}\\n*Email:* {{ $json.clientEmail }}\"\n      }\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "bf014d73-f6d6-4a5d-bc26-7b1c755114e2",
      "name": "Webhook Response - Success",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        4352,
        576
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: true, requestId: $json.requestId, message: 'Proposal sent to ' + $json.clientEmail, total: $json.formattedTotal }) }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "9b2c8db0-9aa9-4426-b413-0fbc2dad4280",
      "name": "Wait - Data",
      "type": "n8n-nodes-base.wait",
      "position": [
        1424,
        688
      ],
      "parameters": {},
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "9a9f6411-d529-48d6-b9c1-14f962cdc58b",
  "connections": {
    "Wait - Data": {
      "main": [
        [
          {
            "node": "JS - Validate and Classify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI - Generate Proposal Copy",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Template - Agency": {
      "main": [
        [
          {
            "node": "JS - Conditional Pricing Logic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Template - Startup": {
      "main": [
        [
          {
            "node": "JS - Conditional Pricing Logic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Proposal Email": {
      "main": [
        [
          {
            "node": "Webhook Response - Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Template - Nonprofit": {
      "main": [
        [
          {
            "node": "JS - Conditional Pricing Logic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait - Review Buffer": {
      "main": [
        [
          {
            "node": "Send Proposal Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log to Google Sheets Tracker",
            "type": "main",
            "index": 0
          },
          {
            "node": "Notify Team - Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Client Data": {
      "main": [
        [
          {
            "node": "Wait - Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Template - Enterprise": {
      "main": [
        [
          {
            "node": "JS - Conditional Pricing Logic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait - Rate Limit Buffer": {
      "main": [
        [
          {
            "node": "AI - Generate Proposal Copy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Validate and Classify": {
      "main": [
        [
          {
            "node": "Filter - Valid Requests Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI - Generate Proposal Copy": {
      "main": [
        [
          {
            "node": "JS - Format Proposal Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Client Type Router": {
      "main": [
        [
          {
            "node": "Template - Startup",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Template - Enterprise",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Template - Agency",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Template - Nonprofit",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Template - Standard Default",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Validation Error Notice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Template - Standard Default": {
      "main": [
        [
          {
            "node": "JS - Conditional Pricing Logic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter - Valid Requests Only": {
      "main": [
        [
          {
            "node": "Switch - Client Type Router",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Format Proposal Document": {
      "main": [
        [
          {
            "node": "Wait - Review Buffer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Conditional Pricing Logic": {
      "main": [
        [
          {
            "node": "Wait - Rate Limit Buffer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll - Hourly Form Submissions": {
      "main": [
        [
          {
            "node": "Normalize Client Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - New Proposal Request": {
      "main": [
        [
          {
            "node": "Normalize Client Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}