{
  "id": "yt4wWVKefnaLtsI5",
  "name": "AI Proposal Generator - Typeform to PandaDoc with GPT-4",
  "tags": [],
  "nodes": [
    {
      "id": "e9b4a85d-c140-4129-b54f-1d28658a63c1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -272,
        -256
      ],
      "parameters": {
        "color": 5,
        "width": 376,
        "height": 824,
        "content": "## \ud83d\udcc4 AI Proposal Generator\n\nAutomatically generate professional, personalized proposals from discovery call intake forms.\n\n### How it works\n1. **Prospect submits** Typeform with project details\n2. **Workflow validates** required fields (email, company)\n3. **AI selects template** based on budget & complexity\n4. **GPT-4 writes** personalized proposal content\n5. **GPT-4 generates** realistic project milestones\n6. **PandaDoc creates** professional document with pricing\n7. **Slack notifies** you with direct link to review\n\n### Setup (15-20 minutes)\n\u2610 Add **OpenAI API** credential (select in GPT nodes)\n\u2610 Add **Typeform API** credential\n\u2610 Add **PandaDoc API** credential (HTTP Header Auth)\n\u2610 Create Typeform with discovery questions\n\u2610 Create 2 PandaDoc templates (Quick Quote + Standard)\n\u2610 Update **Config** node with your company info\n\u2610 Set your **Slack webhook URL** in Config\n\n### Customize\n- Adjust **quickQuoteThreshold** in Config (default: $2,500)\n- Edit GPT prompts to match your writing style\n- Add industry-specific case studies to Config"
      },
      "typeVersion": 1
    },
    {
      "id": "f2581930-af38-4470-a7ae-8123cd0bf1fd",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        144,
        -256
      ],
      "parameters": {
        "color": 5,
        "width": 628,
        "height": 832,
        "content": "## 1. Capture & Extract\n\nThis section handles the intake process:\n\n**Config** \u2192 Stores your company info, PandaDoc template IDs, Slack webhook, and case studies\n\n**Typeform Trigger** \u2192 Fires when prospect submits discovery form\n\n**Extract & Transform Data** \u2192 Parses all form fields, converts budget ranges to numbers, calculates deposit amounts, and determines which template to use"
      },
      "typeVersion": 1
    },
    {
      "id": "05e4268d-3563-433a-89c5-bec383eb66e0",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        816,
        -256
      ],
      "parameters": {
        "color": 5,
        "width": 856,
        "height": 832,
        "content": "## 2. Validate & Route to AI\n\nEnsures data quality before AI processing:\n\n**Check Required Fields** \u2192 Validates email and company name exist (routes to error if missing)\n\n**Route: Quick Quote or Standard?** \u2192 Budget < $2,500 AND not complex \u2192 Quick Quote. Otherwise \u2192 Standard Proposal\n\n**AI: Generate Quick Quote** \u2192 GPT-4 writes concise 1-page quote with benefits and pricing\n\n**AI: Generate Standard Proposal** \u2192 GPT-4 writes detailed multi-page proposal with deliverables and ROI"
      },
      "typeVersion": 1
    },
    {
      "id": "a680aedd-1386-4e66-81c2-37f49f532aab",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1712,
        -256
      ],
      "parameters": {
        "color": 5,
        "width": 824,
        "height": 832,
        "content": "## 3. Parse, Timeline & Merge\n\nProcesses AI output and adds project schedule:\n\n**Parse AI Proposal Response** \u2192 Extracts JSON from GPT response, handles markdown cleanup, merges with form data\n\n**AI: Generate Project Milestones** \u2192 GPT-4 creates 4-phase timeline based on solution complexity\n\n**Parse Milestone Response** \u2192 Extracts timeline JSON with fallback defaults if parsing fails\n\n**Combine Proposal + Milestones** \u2192 Merges proposal content with timeline for complete document data"
      },
      "typeVersion": 1
    },
    {
      "id": "c89b55bb-156c-4744-bc67-0780a426686a",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2560,
        -256
      ],
      "parameters": {
        "color": 5,
        "width": 700,
        "height": 752,
        "content": "## 4. Create PandaDoc\n\nAssembles the final proposal document:\n\n**Check: AI Parse Successful?** \u2192 Routes to error notification if GPT response couldn't be parsed\n\n**Create PandaDoc Document** \u2192 Sends all data to PandaDoc API, populates template tokens, builds pricing table\n\n**Check: Document Created?** \u2192 Verifies PandaDoc returned a document ID"
      },
      "typeVersion": 1
    },
    {
      "id": "0e979740-f949-4041-b675-8c95d239628c",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3280,
        -256
      ],
      "parameters": {
        "color": 5,
        "width": 380,
        "height": 752,
        "content": "## 5. Send Notifications\n\nKeeps you informed of every submission:\n\n**Notify: Proposal Ready** \u2192 Rich Slack message with client name, value, template type, expiry date, and direct PandaDoc link\n\n**Notify: PandaDoc Failed** \u2192 Error details so you can manually follow up with the prospect"
      },
      "typeVersion": 1
    },
    {
      "id": "6bffdc22-e3d6-46ca-bce4-731936108b81",
      "name": "\u2699\ufe0f Config",
      "type": "n8n-nodes-base.set",
      "position": [
        176,
        48
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"senderEmail\": \"user@example.com\",\n  \"senderFirstName\": \"Your\",\n  \"senderLastName\": \"Name\",\n  \"senderCompany\": \"Your Company\",\n  \"senderTitle\": \"Your Title\",\n  \"senderPhone\": \"+1234567890\",\n  \"quickQuoteTemplateId\": \"YOUR_PANDADOC_QUICK_QUOTE_TEMPLATE_ID\",\n  \"standardProposalTemplateId\": \"YOUR_PANDADOC_STANDARD_TEMPLATE_ID\",\n  \"quickQuoteThreshold\": \"2500\",\n  \"slackWebhookUrl\": \"YOUR_SLACK_WEBHOOK_URL\",\n  \"caseStudies\": {\n    \"default\": {\n      \"company\": \"Example Client\",\n      \"industry\": \"Professional Services\",\n      \"results\": \"20+ hours/week saved\",\n      \"testimonial\": \"The ROI was immediate.\"\n    }\n  }\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "62036532-bec5-47ab-8bb5-328e6b8ff47c",
      "name": "\ud83d\udce5 Typeform Trigger",
      "type": "n8n-nodes-base.typeformTrigger",
      "position": [
        384,
        48
      ],
      "parameters": {
        "formId": "YOUR_TYPEFORM_FORM_ID"
      },
      "typeVersion": 1
    },
    {
      "id": "c2a3b89a-aeb2-4aaa-82ff-9e0d8a009959",
      "name": "\ud83d\udd04 Extract & Transform Data",
      "type": "n8n-nodes-base.code",
      "position": [
        592,
        48
      ],
      "parameters": {
        "jsCode": "const config = $('\u2699\ufe0f Config').first().json;\nconst formData = $input.first().json;\n\nconst extractedData = {\n  companyName: formData[\"What's your company name?\"] || '',\n  websiteUrl: formData[\"What's your company website?\"] || '',\n  businessDescription: formData[\"Tell us about your business\"] || '',\n  industry: formData[\"What industry are you in?\"] || '',\n  currentProblem: formData[\"What's your biggest operational challenge?\"] || '',\n  desiredSolution: formData[\"What would the ideal solution look like?\"] || '',\n  platformsToUse: formData[\"What tools/platforms do you currently use?\"] || '',\n  projectComplexity: formData[\"How complex is this project?\"] || '',\n  clientFirstName: formData[\"First name\"] || '',\n  clientLastName: formData[\"Last name\"] || '',\n  clientEmail: formData[\"Email address\"] || '',\n  additionalNotes: formData[\"Anything else we should know?\"] || ''\n};\n\n// Parse budget range to number\nfunction parseBudget(label) {\n  const l = (label || '').toLowerCase();\n  if (l.includes('under') && l.includes('1,500')) return 1250;\n  if (l.includes('1,500') && l.includes('2,500')) return 2000;\n  if (l.includes('2,500') && l.includes('5,000')) return 3750;\n  if (l.includes('5,000') && l.includes('10,000')) return 7500;\n  if (l.includes('10,000+')) return 12500;\n  return 3000;\n}\n\nextractedData.budgetLabel = formData[\"What's your estimated budget?\"] || '';\nextractedData.estimatedValue = parseBudget(extractedData.budgetLabel);\n\n// Template selection logic\nconst threshold = Number(config.quickQuoteThreshold) || 2500;\nconst isComplex = (extractedData.projectComplexity || '').toLowerCase().includes('complex');\n\nextractedData.selectedTemplate = (extractedData.estimatedValue < threshold && !isComplex) ? 'quick_quote' : 'standard';\nextractedData.templateReason = extractedData.selectedTemplate === 'quick_quote' \n  ? `Budget $${extractedData.estimatedValue} < $${threshold}` \n  : `Budget $${extractedData.estimatedValue} >= $${threshold} or complex project`;\nextractedData.pandaDocTemplateId = extractedData.selectedTemplate === 'quick_quote' \n  ? config.quickQuoteTemplateId \n  : config.standardProposalTemplateId;\n\n// Calculate amounts\nextractedData.depositAmount = Math.round(extractedData.estimatedValue * 0.5);\nextractedData.balanceAmount = extractedData.estimatedValue - extractedData.depositAmount;\n\n// Add dates\nconst today = new Date();\nconst validityDays = extractedData.selectedTemplate === 'quick_quote' ? 7 : 14;\nconst expiryDate = new Date(today.getTime() + validityDays * 24 * 60 * 60 * 1000);\nextractedData.documentDate = today.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\nextractedData.proposalExpiryDate = expiryDate.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n\nextractedData.config = config;\nextractedData.caseStudy = config.caseStudies?.default || {};\n\nreturn [{ json: extractedData }];"
      },
      "typeVersion": 2
    },
    {
      "id": "584e5d2e-f38e-479b-853f-49cedfccf7ca",
      "name": "\u2705 Check Required Fields",
      "type": "n8n-nodes-base.if",
      "position": [
        896,
        48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "check-email",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.clientEmail }}",
              "rightValue": ""
            },
            {
              "id": "check-company",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.companyName }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "adc5b18f-b488-45d6-beca-39e2cee0b7b1",
      "name": "\ud83d\udd00 Route: Quick Quote or Standard?",
      "type": "n8n-nodes-base.if",
      "position": [
        1104,
        32
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "check-template",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.selectedTemplate }}",
              "rightValue": "quick_quote"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "cfb596d7-b361-4034-b4dd-a8c35d062037",
      "name": "\ud83e\udd16 AI: Generate Quick Quote",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1328,
        16
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "options": {
          "temperature": 0.7
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a professional proposal writer for an automation agency. Write concise, benefit-focused proposals that emphasize ROI and time savings."
            },
            {
              "content": "=Generate a Quick Quote proposal for this prospective client:\n\n**Company:** {{ $json.companyName }}\n**Industry:** {{ $json.industry }}\n**Their Challenge:** {{ $json.currentProblem }}\n**Desired Outcome:** {{ $json.desiredSolution }}\n**Current Tools:** {{ $json.platformsToUse }}\n**Budget:** ${{ $json.estimatedValue }}\n\nWrite a concise, compelling quick quote. Return ONLY valid JSON (no markdown backticks):\n{\n  \"title\": \"Quick Quote: [specific solution name that addresses their challenge]\",\n  \"challengeSummary\": \"1-2 sentence summary of their pain point in your words\",\n  \"solutionType\": \"Short solution name (e.g., CRM Automation, Lead Follow-up System)\",\n  \"scopeDescription\": \"2-3 sentence description of what you'll build for them\",\n  \"impactBullet1\": \"Specific benefit with metric (e.g., Save 10+ hours/week on manual data entry)\",\n  \"impactBullet2\": \"Second key benefit with metric\",\n  \"impactBullet3\": \"Third key benefit with metric\",\n  \"timeSavings\": \"X hours/week\",\n  \"costSavings\": \"$X/month\"\n}"
            }
          ]
        },
        "jsonOutput": true
      },
      "typeVersion": 1.6
    },
    {
      "id": "06292822-f5ab-4535-b51d-d679e2ceb70b",
      "name": "\ud83e\udd16 AI: Generate Standard Proposal",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1328,
        224
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "options": {
          "temperature": 0.7
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a professional proposal writer for an automation agency. Write detailed, compelling proposals that demonstrate deep understanding of the client's business and clearly articulate ROI."
            },
            {
              "content": "=Generate a detailed Standard Proposal for this prospective client:\n\n**Company:** {{ $json.companyName }}\n**Industry:** {{ $json.industry }}\n**About Their Business:** {{ $json.businessDescription }}\n**Their Challenge:** {{ $json.currentProblem }}\n**Desired Outcome:** {{ $json.desiredSolution }}\n**Current Tools:** {{ $json.platformsToUse }}\n**Project Complexity:** {{ $json.projectComplexity }}\n**Budget:** ${{ $json.estimatedValue }}\n**Additional Context:** {{ $json.additionalNotes }}\n\nWrite a comprehensive, persuasive proposal. Return ONLY valid JSON (no markdown backticks):\n{\n  \"title\": \"Proposal: [specific solution name that addresses their challenge]\",\n  \"challengeSummary\": \"Detailed 2-3 sentence summary demonstrating you understand their pain points\",\n  \"solutionType\": \"Solution name (e.g., End-to-End Sales Automation Platform)\",\n  \"scopeDescription\": \"Detailed 3-4 sentence scope of work explaining exactly what you'll deliver\",\n  \"impactBullet1\": \"Specific benefit with metric (e.g., Reduce lead response time from 24 hours to under 5 minutes)\",\n  \"impactBullet2\": \"Second key benefit with specific metric\",\n  \"impactBullet3\": \"Third key benefit with specific metric\",\n  \"outcomeProcess1\": \"Concrete deliverable 1 (e.g., Automated lead capture and CRM sync)\",\n  \"outcomeProcess2\": \"Concrete deliverable 2\",\n  \"outcomeProcess3\": \"Concrete deliverable 3\",\n  \"timeSavings\": \"X hours/week\",\n  \"costSavings\": \"$X/month\"\n}"
            }
          ]
        },
        "jsonOutput": true
      },
      "typeVersion": 1.6
    },
    {
      "id": "dce6e920-f7e8-4e3b-9771-20df29e58ccb",
      "name": "\ud83d\udccb Parse AI Proposal Response",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        128
      ],
      "parameters": {
        "jsCode": "// Parse GPT response and merge with extracted data\nconst raw = $input.first().json;\nconst extractedData = $('\ud83d\udd04 Extract & Transform Data').first().json;\n\nlet content = raw.message?.content ?? raw.content ?? raw;\n\ntry {\n  if (typeof content === 'string') {\n    // Remove markdown code blocks if present\n    content = content.replace(/```json\\s*/g, '').replace(/```\\s*/g, '').trim();\n    content = JSON.parse(content);\n  }\n  \n  // Merge GPT response with extracted form data\n  return [{ \n    json: { \n      ...extractedData,\n      ...content, \n      proposalParseOk: true \n    } \n  }];\n} catch (e) {\n  return [{ \n    json: { \n      ...extractedData,\n      proposalParseOk: false, \n      proposalParseError: e.message \n    } \n  }];\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "c02eb059-c2a6-4c32-b6c8-717d14b92fa1",
      "name": "\ud83e\udd16 AI: Generate Project Milestones",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1936,
        0
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "options": {
          "temperature": 0.5
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a project manager who creates realistic, client-friendly project timelines for automation projects."
            },
            {
              "content": "=Generate a 4-phase project timeline for this automation project:\n\n**Solution Being Built:** {{ $json.solutionType }}\n**Scope of Work:** {{ $json.scopeDescription }}\n**Project Complexity:** {{ $('\ud83d\udd04 Extract & Transform Data').first().json.projectComplexity }}\n\nCreate realistic milestones that set proper client expectations. Return ONLY valid JSON (no markdown backticks):\n{\n  \"milestone1\": \"Phase 1: [Discovery & Planning - specific activities]\",\n  \"timeline1\": \"Week 1\",\n  \"milestone2\": \"Phase 2: [Build & Configure - specific deliverables]\",\n  \"timeline2\": \"Week 2\",\n  \"milestone3\": \"Phase 3: [Testing & Refinement - specific activities]\",\n  \"timeline3\": \"Week 3\",\n  \"milestone4\": \"Phase 4: [Launch & Handoff - specific deliverables]\",\n  \"timeline4\": \"Week 4\"\n}"
            }
          ]
        },
        "jsonOutput": true
      },
      "typeVersion": 1.6
    },
    {
      "id": "711ec080-9ae2-442b-b984-2e238481db7e",
      "name": "\ud83d\udccb Parse Milestone Response",
      "type": "n8n-nodes-base.code",
      "position": [
        2272,
        0
      ],
      "parameters": {
        "jsCode": "// Parse milestones with fallback defaults\nconst raw = $input.first().json;\nlet content = raw.message?.content ?? raw.content ?? raw;\n\ntry {\n  if (typeof content === 'string') {\n    content = content.replace(/```json\\s*/g, '').replace(/```\\s*/g, '').trim();\n    content = JSON.parse(content);\n  }\n  return [{ json: { ...content, milestonesParseOk: true } }];\n} catch (e) {\n  // Return default milestones on parse error\n  return [{ json: {\n    milestone1: 'Phase 1: Discovery - Requirements gathering and solution design',\n    timeline1: 'Week 1',\n    milestone2: 'Phase 2: Build - Configure and develop core automation workflows',\n    timeline2: 'Week 2',\n    milestone3: 'Phase 3: Test - Quality assurance and refinements',\n    timeline3: 'Week 3',\n    milestone4: 'Phase 4: Launch - Training, documentation, and go-live support',\n    timeline4: 'Week 4',\n    milestonesParseOk: false,\n    milestonesParseError: e.message\n  } }];\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "e3841932-fe5b-422f-9cb5-c99f96aa1d9d",
      "name": "\ud83d\udd17 Combine Proposal + Milestones",
      "type": "n8n-nodes-base.merge",
      "position": [
        1968,
        240
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3
    },
    {
      "id": "dc40c4b6-3362-4708-9285-0ca50b4f8f31",
      "name": "\u2705 Check: AI Parse Successful?",
      "type": "n8n-nodes-base.if",
      "position": [
        2688,
        240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "check-parse",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.proposalParseOk }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "d5ab459d-2d7a-4ae0-9086-607c58690cd3",
      "name": "\ud83d\udcc4 Create PandaDoc Document",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2912,
        224
      ],
      "parameters": {
        "url": "https://api.pandadoc.com/public/v1/documents",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "jsonBody": "={\n  \"name\": \"{{ $json.title }} - {{ $json.companyName }}\",\n  \"template_uuid\": \"{{ $json.pandaDocTemplateId }}\",\n  \"recipients\": [\n    {\n      \"email\": \"{{ $json.clientEmail }}\",\n      \"first_name\": \"{{ $json.clientFirstName }}\",\n      \"last_name\": \"{{ $json.clientLastName }}\",\n      \"role\": \"Client\"\n    }\n  ],\n  \"tokens\": [\n    { \"name\": \"Client.Company\", \"value\": \"{{ $json.companyName }}\" },\n    { \"name\": \"Client.FirstName\", \"value\": \"{{ $json.clientFirstName }}\" },\n    { \"name\": \"Client.LastName\", \"value\": \"{{ $json.clientLastName }}\" },\n    { \"name\": \"Client.ChallengeSummary\", \"value\": \"{{ $json.challengeSummary }}\" },\n    { \"name\": \"Project.Total\", \"value\": \"{{ $json.estimatedValue }}\" },\n    { \"name\": \"Project.Deposit\", \"value\": \"{{ $json.depositAmount }}\" },\n    { \"name\": \"Project.TimeSavings\", \"value\": \"{{ $json.timeSavings }}\" },\n    { \"name\": \"Project.CostSavings\", \"value\": \"{{ $json.costSavings }}\" },\n    { \"name\": \"Timeline.Phase1\", \"value\": \"{{ $json.milestone1 }}\" },\n    { \"name\": \"Timeline.Phase1Date\", \"value\": \"{{ $json.timeline1 }}\" },\n    { \"name\": \"Timeline.Phase2\", \"value\": \"{{ $json.milestone2 }}\" },\n    { \"name\": \"Timeline.Phase2Date\", \"value\": \"{{ $json.timeline2 }}\" },\n    { \"name\": \"Timeline.Phase3\", \"value\": \"{{ $json.milestone3 }}\" },\n    { \"name\": \"Timeline.Phase3Date\", \"value\": \"{{ $json.timeline3 }}\" },\n    { \"name\": \"Timeline.Phase4\", \"value\": \"{{ $json.milestone4 }}\" },\n    { \"name\": \"Timeline.Phase4Date\", \"value\": \"{{ $json.timeline4 }}\" },\n    { \"name\": \"Impact.Bullet1\", \"value\": \"{{ $json.impactBullet1 }}\" },\n    { \"name\": \"Impact.Bullet2\", \"value\": \"{{ $json.impactBullet2 }}\" },\n    { \"name\": \"Impact.Bullet3\", \"value\": \"{{ $json.impactBullet3 }}\" },\n    { \"name\": \"Proposal.ExpiryDate\", \"value\": \"{{ $json.proposalExpiryDate }}\" },\n    { \"name\": \"Document.Date\", \"value\": \"{{ $json.documentDate }}\" }\n  ],\n  \"pricing_tables\": [\n    {\n      \"name\": \"Pricing Table 1\",\n      \"sections\": [\n        {\n          \"title\": \"Project Investment\",\n          \"default\": true,\n          \"rows\": [\n            {\n              \"options\": { \"qty_editable\": false, \"optional\": false },\n              \"data\": {\n                \"name\": \"{{ $json.solutionType }}\",\n                \"description\": \"{{ $json.scopeDescription }}\",\n                \"price\": {{ $json.estimatedValue }},\n                \"qty\": 1\n              }\n            }\n          ]\n        }\n      ],\n      \"options\": {\n        \"currency\": \"USD\",\n        \"discount\": { \"type\": \"absolute\", \"name\": \"Discount\", \"value\": 0 }\n      }\n    }\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "2e9b50b3-85e0-4589-a4ea-06215dfe89c6",
      "name": "\u2705 Check: Document Created?",
      "type": "n8n-nodes-base.if",
      "position": [
        3104,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "check-id",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "26eba8d4-81e9-4994-916f-545d9301d232",
      "name": "\ud83d\udcac Notify: Proposal Ready",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3424,
        96
      ],
      "parameters": {
        "url": "={{ $('\u2699\ufe0f Config').first().json.slackWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  \"text\": \"\u2705 Proposal Created!\",\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": { \"type\": \"plain_text\", \"text\": \"\u2705 New Proposal Generated\", \"emoji\": true }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        { \"type\": \"mrkdwn\", \"text\": \"*Client:*\\n\" + $('\ud83d\udd04 Extract & Transform Data').first().json.companyName },\n        { \"type\": \"mrkdwn\", \"text\": \"*Value:*\\n$\" + $('\ud83d\udd04 Extract & Transform Data').first().json.estimatedValue },\n        { \"type\": \"mrkdwn\", \"text\": \"*Template:*\\n\" + ($('\ud83d\udd04 Extract & Transform Data').first().json.selectedTemplate === 'quick_quote' ? '\ud83d\udccb Quick Quote' : '\ud83d\udcc4 Standard Proposal') },\n        { \"type\": \"mrkdwn\", \"text\": \"*Expires:*\\n\" + $('\ud83d\udd04 Extract & Transform Data').first().json.proposalExpiryDate }\n      ]\n    },\n    {\n      \"type\": \"actions\",\n      \"elements\": [\n        {\n          \"type\": \"button\",\n          \"text\": { \"type\": \"plain_text\", \"text\": \"\ud83d\udcc4 View in PandaDoc\", \"emoji\": true },\n          \"url\": \"https://app.pandadoc.com/a/#/documents/\" + $json.id\n        }\n      ]\n    }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "04b2ac5e-9ad6-46f4-8d03-e03b1808a329",
      "name": "\ud83d\udea8 Notify: PandaDoc Failed",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3424,
        288
      ],
      "parameters": {
        "url": "={{ $('\u2699\ufe0f Config').first().json.slackWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  \"text\": \"\u274c PandaDoc Error\",\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": { \"type\": \"plain_text\", \"text\": \"\u274c PandaDoc Creation Failed\", \"emoji\": true }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        { \"type\": \"mrkdwn\", \"text\": \"*Client:*\\n\" + $('\ud83d\udd04 Extract & Transform Data').first().json.companyName },\n        { \"type\": \"mrkdwn\", \"text\": \"*Email:*\\n\" + $('\ud83d\udd04 Extract & Transform Data').first().json.clientEmail },\n        { \"type\": \"mrkdwn\", \"text\": \"*Template:*\\n\" + $('\ud83d\udd04 Extract & Transform Data').first().json.selectedTemplate }\n      ]\n    },\n    {\n      \"type\": \"section\",\n      \"text\": { \"type\": \"mrkdwn\", \"text\": \"*Error:* \" + ($json.message || $json.error || 'Unknown error - check PandaDoc API credentials and template IDs') }\n    }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "1f79534f-5d09-4b86-bcdc-0dedb03b77c8",
      "name": "\ud83d\udea8 Notify: GPT Parse Failed",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1040,
        768
      ],
      "parameters": {
        "url": "={{ $('\u2699\ufe0f Config').first().json.slackWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  \"text\": \"\u26a0\ufe0f GPT Parse Error\",\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": { \"type\": \"plain_text\", \"text\": \"\u26a0\ufe0f AI Response Parse Failed\", \"emoji\": true }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        { \"type\": \"mrkdwn\", \"text\": \"*Client:*\\n\" + $json.companyName },\n        { \"type\": \"mrkdwn\", \"text\": \"*Email:*\\n\" + $json.clientEmail },\n        { \"type\": \"mrkdwn\", \"text\": \"*Template:*\\n\" + $json.selectedTemplate }\n      ]\n    },\n    {\n      \"type\": \"section\",\n      \"text\": { \"type\": \"mrkdwn\", \"text\": \"*Error:* \" + ($json.proposalParseError || 'GPT returned invalid JSON - you may need to manually create this proposal') }\n    }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "67f4d00b-f241-4b14-975c-d02ed6eb1ecb",
      "name": "\ud83d\udea8 Notify: Missing Required Fields",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1312,
        768
      ],
      "parameters": {
        "url": "={{ $('\u2699\ufe0f Config').first().json.slackWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  \"text\": \"\u26a0\ufe0f Validation Failed\",\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": { \"type\": \"plain_text\", \"text\": \"\u26a0\ufe0f Form Missing Required Fields\", \"emoji\": true }\n    },\n    {\n      \"type\": \"section\",\n      \"text\": { \"type\": \"mrkdwn\", \"text\": \"A Typeform submission was received but is missing required fields:\\n\\n*Email:* \" + ($json.clientEmail || '\u274c Missing') + \"\\n*Company:* \" + ($json.companyName || '\u274c Missing') + \"\\n\\n_This prospect may need manual follow-up if you have other contact info._\" }\n    }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "1d379c06-c99a-4313-a863-57917963c66a",
      "name": "Sticky Note Error",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        624
      ],
      "parameters": {
        "color": 6,
        "width": 1156,
        "height": 360,
        "content": "## \u26a0\ufe0f Error Handling\n\nCaptures issues at every stage:\n\n**Notify: GPT Parse Failed** \u2192 AI response wasn't valid JSON\n\n**Notify: Missing Required Fields** \u2192 Form submitted without email or company name\n\nBoth errors include client details so you can manually reach out"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "a9ce8e74-18da-448b-ac01-7e4f52a52b6b",
  "connections": {
    "\ud83d\udce5 Typeform Trigger": {
      "main": [
        [
          {
            "node": "\ud83d\udd04 Extract & Transform Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2705 Check Required Fields": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Route: Quick Quote or Standard?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udea8 Notify: Missing Required Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2705 Check: Document Created?": {
      "main": [
        [
          {
            "node": "\ud83d\udcac Notify: Proposal Ready",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udea8 Notify: PandaDoc Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcc4 Create PandaDoc Document": {
      "main": [
        [
          {
            "node": "\u2705 Check: Document Created?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udccb Parse Milestone Response": {
      "main": [
        [
          {
            "node": "\ud83d\udd17 Combine Proposal + Milestones",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd04 Extract & Transform Data": {
      "main": [
        [
          {
            "node": "\u2705 Check Required Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udd16 AI: Generate Quick Quote": {
      "main": [
        [
          {
            "node": "\ud83d\udccb Parse AI Proposal Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2705 Check: AI Parse Successful?": {
      "main": [
        [
          {
            "node": "\ud83d\udcc4 Create PandaDoc Document",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udea8 Notify: GPT Parse Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udccb Parse AI Proposal Response": {
      "main": [
        [
          {
            "node": "\ud83e\udd16 AI: Generate Project Milestones",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\udd17 Combine Proposal + Milestones",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "\ud83d\udd17 Combine Proposal + Milestones": {
      "main": [
        [
          {
            "node": "\u2705 Check: AI Parse Successful?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udd16 AI: Generate Standard Proposal": {
      "main": [
        [
          {
            "node": "\ud83d\udccb Parse AI Proposal Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd00 Route: Quick Quote or Standard?": {
      "main": [
        [
          {
            "node": "\ud83e\udd16 AI: Generate Quick Quote",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83e\udd16 AI: Generate Standard Proposal",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udd16 AI: Generate Project Milestones": {
      "main": [
        [
          {
            "node": "\ud83d\udccb Parse Milestone Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}