{
  "meta": {
    "instanceId": "fe849132d8c0d46a6070ebd60698d892cd65ebc032ada4e7af186e0f756c61a0",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "6a71b550-8237-4761-aa17-bf3633012aa8",
      "name": "Generate Personalized Email",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        320,
        -640
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-flash-lite",
          "cachedResultName": "models/gemini-2.5-flash-lite"
        },
        "options": {
          "temperature": 0.4
        },
        "messages": {
          "values": [
            {
              "content": "=You are Daniel, a finance mortgage broker at Lendium in Australia. Write a professional, warm 3-4 sentence email to {{ $('Normalize lead name').item.json.first_name }} who just inquired about a {{ $('Normalize lead name').item.json.loan_type }} with an income of ${{ $('Normalize lead name').item.json.income }}.\n\nInclude:\n1. Thank them for their inquiry\n2. Acknowledge their specific loan type and mention one relevant insight about their situation\n3. Provide a clear next step (ask them to upload required documents on link provided below)\n4. Sign off professionally as Daniel from Lendium\n\n\nKeep the tone professional yet approachable. Return ONLY the email body text, no subject line."
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "credential-id",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "bea5b817-6759-44dd-af3d-09721b7b1b5a",
      "name": "Create Gmail Draft",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1120,
        -640
      ],
      "webhookId": "53109ca8-e71e-4800-9432-db4bec6f3522",
      "parameters": {
        "message": "={{ $('Generate Personalized Email').item.json.content.parts[0].text }}\n\\n\\n\n<a href=\"https://13.211.164.241.nip.io/form/df9aebf7-3e4f-4114-bc43-424c3df3511e?folder_id={{ $node['Create Drive Folder'].json.id }}&client_name={{ $('Normalize lead name').item.json.first_name }}\"style=\"background-color: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px;\">Upload Folder</a>",
        "options": {
          "sendTo": "={{ $('Normalize lead name').item.json.email }}"
        },
        "subject": "=Re: Your {{ $('Normalize lead name').item.json.loan_type }} Inquiry - Lendium Mortgage Services",
        "resource": "draft",
        "emailType": "html"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "credential-id",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "37d4f043-78a6-4615-abfe-02c4946660f2",
      "name": "Aggregate Log Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1568,
        -640
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Aggregate all workflow data including errors and email approval status\nconst item = $input.item;\n\n// Initialize the aggregated data object\nconst aggregatedData = {\n  // Get email approval status from the Request Email Approval node\n  email_approved: null,\n  \n  // Initialize error tracking\n  lead_activity_error_details: null,\n  \n  // Preserve other important data\n  lead_first_name: null,\n  email: null\n};\n\ntry {\n  // 1. CAPTURE EMAIL APPROVAL STATUS\n  // Check if the approval node executed successfully\n  const approvalNode = $('Request Email Approval').item?.json;\n  \n  if (approvalNode) {\n    // The approval response is typically in the 'update' or 'message' field\n    // Telegram approval returns 'approve' or 'decline'\n    aggregatedData.email_approved = approvalNode.update?.callback_query?.data === 'approve' || \n                                    approvalNode.message?.text?.toLowerCase().includes('yes') ||\n                                    approvalNode.approved === true;\n  }\n  \n  // 2. CAPTURE ANY ERRORS FROM THE WORKFLOW\n  const errors = [];\n  \n  // Check each node for errors\n  const nodesToCheck = [\n    'Generate Strategy Insights',\n    'Generate Personalized Email',\n    'Create Drive Folder',\n    'Share Drive Folder',\n    'Store in Database',\n    'Create Gmail Draft'\n  ];\n  \n  nodesToCheck.forEach(nodeName => {\n    try {\n      const nodeData = $(nodeName).item?.json;\n      if (nodeData?.error || nodeData?.message?.includes('error')) {\n        errors.push({\n          node: nodeName,\n          error: nodeData.error || nodeData.message,\n          timestamp: new Date().toISOString()\n        });\n      }\n    } catch (e) {\n      // Node might not have executed, skip it\n    }\n  });\n  \n  // 3. FORMAT ERROR DETAILS\n  if (errors.length > 0) {\n    aggregatedData.lead_activity_error_details = JSON.stringify({\n      error_count: errors.length,\n      errors: errors,\n      workflow_completed: false\n    });\n  } else {\n    aggregatedData.lead_activity_error_details = JSON.stringify({\n      error_count: 0,\n      errors: [],\n      workflow_completed: true,\n      completed_at: new Date().toISOString()\n    });\n  }\n  \n  // 4. CAPTURE LEAD INFORMATION FOR REFERENCE\n  const webhookData = $('Typebot Webhook').item?.json?.body;\n  if (webhookData) {\n    aggregatedData.lead_first_name = webhookData.first_name;\n    aggregatedData.email = webhookData.email;\n  }\n  \n} catch (error) {\n  // If aggregation itself fails, log that error\n  aggregatedData.lead_activity_error_details = JSON.stringify({\n    error_count: 1,\n    errors: [{\n      node: 'Aggregate Log Data',\n      error: error.message,\n      timestamp: new Date().toISOString()\n    }],\n    workflow_completed: false\n  });\n}\n\n// Return the aggregated data\nreturn {\n  json: aggregatedData\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "8573b74a-e099-4d26-a557-ae769a797710",
      "name": "Create Drive Folder",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        672,
        -640
      ],
      "parameters": {
        "name": "={{ $('Normalize lead name').item.json.first_name }} ({{ $('Normalize lead name').item.json.loan_type }})",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "1vleObg6ZBzUflpAVT2Joc5D7oBNYWNUw",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1vleObg6ZBzUflpAVT2Joc5D7oBNYWNUw",
          "cachedResultName": "Lendium Files"
        },
        "resource": "folder"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "credential-id",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "00bca220-c70d-4ef0-8c64-84b5bedeca80",
      "name": "Share Drive Folder",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        896,
        -640
      ],
      "parameters": {
        "options": {},
        "resource": "folder",
        "operation": "share",
        "permissionsUi": {
          "permissionsValues": {
            "role": "writer",
            "type": "anyone"
          }
        },
        "folderNoRootId": {
          "__rl": true,
          "mode": "id",
          "value": "=1YJ026YLa4IT-rk-AqCUlHcdWaxvhDPLE"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "credential-id",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "68481bfe-c542-4417-9fcf-368b0b0d5bcb",
      "name": "Store in Database",
      "type": "n8n-nodes-base.supabase",
      "position": [
        1792,
        -640
      ],
      "parameters": {
        "tableId": "leads_consolidated",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "lead_first_name",
              "fieldValue": "={{ $('Normalize lead name').item.json.first_name }}"
            },
            {
              "fieldId": "email",
              "fieldValue": "={{ $('Normalize lead name').item.json.email }}"
            },
            {
              "fieldId": "loan_type",
              "fieldValue": "={{ $('Normalize lead name').item.json.loan_type }}"
            },
            {
              "fieldId": "income",
              "fieldValue": "={{ $('Normalize lead name').item.json.income }}"
            },
            {
              "fieldId": "folder_link",
              "fieldValue": "=https://drive.google.com/drive/u/0/folders/{{ $('Create Drive Folder').item.json.id }}"
            },
            {
              "fieldId": "lead_last_name",
              "fieldValue": "={{ $('Normalize lead name').item.json.last_name }}"
            },
            {
              "fieldId": "created_at",
              "fieldValue": "={{ $now }}"
            },
            {
              "fieldId": "upload_form_link",
              "fieldValue": "=https://n8n.io/form/df9aebf7-3e4f-4114-bc43-424c3df3511e?folder_id={{ $('Create Drive Folder').item.json.id }}&client_name={{ $('Normalize lead name').item.json.first_name }}"
            },
            {
              "fieldId": "residency_status",
              "fieldValue": "={{ $('Normalize lead name').item.json.residency_status }}"
            },
            {
              "fieldId": "email_approved",
              "fieldValue": "Approved"
            },
            {
              "fieldId": "lead_activity_error_details",
              "fieldValue": "={{ $json.lead_activity_error_details }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "id": "credential-id",
          "name": "Supabase account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "773a1dd9-0cd8-439f-af0c-e47bb0f4bc95",
      "name": "Validate Input",
      "type": "n8n-nodes-base.if",
      "position": [
        -608,
        192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "validation-1",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.folder_id }}",
              "rightValue": ""
            },
            {
              "id": "validation-2",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.client_name }}",
              "rightValue": ""
            },
            {
              "id": "validation-3",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ Object.keys($binary).length }}",
              "rightValue": 3
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "287b67ee-910c-434c-ac65-fae098b55318",
      "name": "Send Success Notification",
      "type": "n8n-nodes-base.telegram",
      "position": [
        736,
        96
      ],
      "webhookId": "0d46ecfd-ed07-4ba4-aba4-4f072e5107c6",
      "parameters": {
        "text": "=✅ *All Documents Uploaded Successfully*\n\n👤 *Client:* {{ $('Upload portal trigger').item.json.formQueryParameters.client_name }}\n📁 *Folder:* [View Folder](https://drive.google.com/drive/u/0/folders/{{ $('Upload portal trigger').item.json.folder_id }})",
        "chatId": "123456789",
        "additionalFields": {
          "parse_mode": "Markdown",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "id": "credential-id",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f0e07519-5def-4db1-a9df-123c01435aee",
      "name": "Send Partial Failure Notification",
      "type": "n8n-nodes-base.telegram",
      "position": [
        736,
        288
      ],
      "webhookId": "e0284837-dffb-4f57-a23e-062a7fd39e7f",
      "parameters": {
        "text": "=⚠️ *Partial Upload Failure*\n\n👤 *Client:* {{ $json.client_name }}\n📅 *Time:* {{ $json.timestamp }}\n\n✅ *Successful:* {{ $json.successful_count }}/3\n{{ $json.successful_uploads.length > 0 ? $json.successful_uploads.map(u => `• ${u.name}: ${u.filename}`).join('\\n') : 'None' }}\n\n❌ *Failed:* {{ $json.failed_count }}/3\n{{ $json.failed_uploads.map(f => `• ${f.name}: ${f.filename}\\n  Error: ${f.error}`).join('\\n') }}\n\n📁 [View Folder]({{ $json.folder_link }})\n\n*Action Required:* Please contact the client to re-upload failed documents.",
        "chatId": "123456789",
        "additionalFields": {
          "parse_mode": "Markdown",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "id": "credential-id",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "545688ea-8362-4ac0-95b4-1b2829012792",
      "name": "Send Validation Error",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -384,
        288
      ],
      "webhookId": "2ed6ebf3-b9b1-427b-8c35-926392eeaf29",
      "parameters": {
        "text": "=❌ *Validation Failed*\n\n📅 *Time:* {{ $now.toISO() }}\n\n*Issue:* Form submission failed validation checks.\n\nPossible reasons:\n• Missing folder_id or client_name\n• Not all 3 files were uploaded\n• Invalid form data\n\nPlease check the form configuration and try again.",
        "chatId": "123456789",
        "additionalFields": {
          "parse_mode": "Markdown",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "id": "credential-id",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "1efd1ad3-21d6-455e-9a23-7af5943c12b2",
      "name": "Upload ID1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -384,
        96
      ],
      "parameters": {
        "name": "={{ $('Upload portal trigger').item.binary.ID.fileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive",
          "cachedResultName": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Upload portal trigger').item.json.folder_id }}"
        },
        "inputDataFieldName": "={{ $('Upload portal trigger').item.binary.ID }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "credential-id",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3,
      "continueOnFail": true
    },
    {
      "id": "80ef637a-2997-4084-8acc-58531f4836c0",
      "name": "Upload Payslip1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -160,
        96
      ],
      "parameters": {
        "name": "={{ $('Upload portal trigger').item.binary.Payslip.fileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive",
          "cachedResultName": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Upload portal trigger').item.json.folder_id }}"
        },
        "inputDataFieldName": "={{ $('Upload portal trigger').item.binary.Payslip }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "credential-id",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3,
      "continueOnFail": true
    },
    {
      "id": "dddb0d6e-0641-462b-89a5-22b672b3b5af",
      "name": "Upload Bank Statement1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        64,
        96
      ],
      "parameters": {
        "name": "={{ $('Upload portal trigger').item.binary['Bank_Statement'].fileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive",
          "cachedResultName": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Upload portal trigger').item.json.folder_id }}"
        },
        "inputDataFieldName": "={{ $('Upload portal trigger').item.binary['Bank_Statement'] }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "credential-id",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3,
      "continueOnFail": true
    },
    {
      "id": "15775092-8702-4a1c-8ee4-3f4022f3ebed",
      "name": "Send Email Created Confirmation",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1344,
        -640
      ],
      "webhookId": "confirmation-webhook-id",
      "parameters": {
        "text": "=📧 Draft Email Ready for {{ $('Normalize lead name').item.json.first_name }}.\n\n\n{{ $('Generate Personalized Email').item.json.content.parts[0].text }}\n\n\n📁 *Folder:* [View Folder](https://drive.google.com/drive/u/0/folders/{{ $('Create Drive Folder').item.json.id }})\n\n\n✅ Check your Gmail drafts to review and send.",
        "chatId": "123456789",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "id": "credential-id",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "fbcff950-a080-4366-b781-954deedc9915",
      "name": "Request Email Approval1",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -128,
        -544
      ],
      "webhookId": "1be7b923-cffd-45b6-b9fc-652039170d2b",
      "parameters": {
        "chatId": "123456789",
        "message": "=🚀 URGENT: High-Quality Lead!\n\n👤 Full Name: {{ $('Normalize lead name').item.json.full_name_clean }}\n📧 Email: {{ $('Normalize lead name').item.json.email }}\n💰 Income: ${{ $('Normalize lead name').item.json.income }}\n🏠 Loan Type: {{ $('Normalize lead name').item.json.loan_type }}\n📍 Residency: {{ $('Normalize lead name').item.json.residency_status }}\n\n---\n\nApprove to draft the email?",
        "options": {
          "appendAttribution": false
        },
        "operation": "sendAndWait",
        "approvalOptions": {
          "values": {
            "approvalType": "double"
          }
        }
      },
      "credentials": {
        "telegramApi": {
          "id": "credential-id",
          "name": "Telegram account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5d9a6fd3-5fa9-4c05-aa98-acbea93ad832",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -800,
        -544
      ],
      "webhookId": "29e8d609-d997-47bb-bc8b-71a5a3a26119",
      "parameters": {
        "options": {},
        "formTitle": "Provide Your details",
        "formFields": {
          "values": [
            {
              "fieldName": "name",
              "fieldLabel": "Name",
              "requiredField": true
            },
            {
              "fieldName": "email",
              "fieldType": "email",
              "fieldLabel": "Email",
              "requiredField": true
            },
            {
              "fieldName": "loan_type",
              "fieldType": "radio",
              "fieldLabel": "Looking to see if we can help with your loan?",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Home Loan"
                  },
                  {
                    "option": "Commercial"
                  },
                  {
                    "option": "Refinance"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldName": "income",
              "fieldType": "number",
              "fieldLabel": "Income in AUD",
              "requiredField": true
            },
            {
              "fieldName": "residency_status",
              "fieldType": "radio",
              "fieldLabel": "Are you an AU citizen?",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Yes"
                  },
                  {
                    "option": "No"
                  }
                ]
              },
              "requiredField": true
            }
          ]
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "473bacef-d6d5-41f6-ab86-6d2a755de5ad",
      "name": "Check income threshold",
      "type": "n8n-nodes-base.if",
      "position": [
        -352,
        -544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "7d175798-af1e-4718-88d0-85bcc361b8f1",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.income }}",
              "rightValue": 80000
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "52793993-e72c-4926-8b69-a4437f35355b",
      "name": "Check approval response",
      "type": "n8n-nodes-base.if",
      "position": [
        96,
        -544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "7d175798-af1e-4718-88d0-85bcc361b8f1",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "746733a1-676c-4b04-9b5a-5b9e2d496a88",
      "name": "Check all uploads successful",
      "type": "n8n-nodes-base.if",
      "position": [
        512,
        192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "9c0bfdd5-4456-44a4-b8dd-611d7f25f0d5",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.all_success }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ba73f9f0-970c-41c4-8806-c9438b489089",
      "name": "Normalize lead name",
      "type": "n8n-nodes-base.code",
      "position": [
        -576,
        -544
      ],
      "parameters": {
        "jsCode": "// Get and clean input\nconst fullNameRaw = $input.first().json.name.trim().toLowerCase();\n\n// Function to capitalize first letter of each word\nfunction toTitleCase(str) {\n  return str.replace(/\\b\\w/g, char => char.toUpperCase());\n}\n\n// Normalize full name\nconst normalizedFullName = toTitleCase(fullNameRaw);\n\n// Split into parts\nconst parts = normalizedFullName.split(/\\s+/);\n\nconst firstName = parts[0] || '';\nconst lastName = parts.length > 1 ? parts.slice(1).join(' ') : '';\n\n\n// Return the data with parsed names\nreturn {\n  json: {\n    ...($input.first().json),\n    first_name: firstName,\n    last_name: lastName,\n    full_name_clean: normalizedFullName\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "3799e719-fae7-47e7-9998-012dd70d0114",
      "name": "Evaluate upload results",
      "type": "n8n-nodes-base.code",
      "position": [
        288,
        96
      ],
      "parameters": {
        "jsCode": "// Get all upload results\nconst uploads = $input.all();\n\n// Track results\nconst successful = [];\nconst failed = [];\n\n// Check each upload\nuploads.forEach((upload, index) => {\n  const docType = index === 0 ? 'ID' : index === 1 ? 'Payslip' : 'Bank_Statement';\n  \n  if (upload.json.error) {\n    // Upload failed\n    failed.push({\n      document: docType,\n      error: upload.json.error\n    });\n  } else {\n    // Upload succeeded\n    successful.push({\n      document: docType,\n      file_id: upload.json.id,\n      link: upload.json.webViewLink\n    });\n  }\n});\n\n// Check if all successful\nconst allSuccess = failed.length === 0;\n\n// Prepare error details for Supabase (store as JSON string or null)\nconst errorDetails = failed.length > 0 ? JSON.stringify(failed) : null;\n\nreturn {\n  json: {\n    all_success: allSuccess,\n    document_upload_error_details: errorDetails,\n    successful_uploads: successful,\n    failed_uploads: failed,\n    successful_count: successful.length,\n    failed_count: failed.length\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "6f89d4a0-33d7-468a-8520-d4c5858ec503",
      "name": "Log declined lead",
      "type": "n8n-nodes-base.supabase",
      "position": [
        384,
        -448
      ],
      "parameters": {
        "tableId": "leads_consolidated",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "lead_first_name",
              "fieldValue": "={{ $('Normalize lead name').item.json.first_name }}"
            },
            {
              "fieldId": "email",
              "fieldValue": "={{ $('Normalize lead name').item.json.email }}"
            },
            {
              "fieldId": "loan_type",
              "fieldValue": "={{ $('Normalize lead name').item.json.loan_type }}"
            },
            {
              "fieldId": "income",
              "fieldValue": "={{ $('Normalize lead name').item.json.income }}"
            },
            {
              "fieldId": "lead_last_name",
              "fieldValue": "={{ $('Normalize lead name').item.json.last_name }}"
            },
            {
              "fieldId": "created_at",
              "fieldValue": "={{ $now }}"
            },
            {
              "fieldId": "residency_status",
              "fieldValue": "={{ $('On form submission').item.json.residency_status }}"
            },
            {
              "fieldId": "email_approved",
              "fieldValue": "Declined"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "id": "credential-id",
          "name": "Supabase account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7b7e5098-2931-4403-8ce4-6f43336cb220",
      "name": "Update upload error log",
      "type": "n8n-nodes-base.supabase",
      "position": [
        512,
        0
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "lead_first_name",
              "keyValue": "={{ $('Upload portal trigger').item.json.client_name }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "leads_consolidated",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "document_upload_error_details",
              "fieldValue": "={{ $json.document_upload_error_details }}"
            }
          ]
        },
        "matchType": "allFilters",
        "operation": "update"
      },
      "credentials": {
        "supabaseApi": {
          "id": "credential-id",
          "name": "Supabase account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "368ba308-d5ae-4cb1-a315-beb9115cd6b2",
      "name": "Upload portal trigger",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -832,
        192
      ],
      "webhookId": "df9aebf7-3e4f-4114-bc43-424c3df3511e",
      "parameters": {
        "options": {},
        "formTitle": "Document Upload Portal",
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "ID",
              "requiredField": true
            },
            {
              "fieldType": "file",
              "fieldLabel": "Payslip",
              "requiredField": true
            },
            {
              "fieldType": "file",
              "fieldLabel": "Bank_Statement",
              "requiredField": true
            },
            {
              "fieldName": "folder_id",
              "fieldType": "hiddenField"
            },
            {
              "fieldName": "client_name",
              "fieldType": "hiddenField"
            }
          ]
        },
        "formDescription": "Please upload your documents here. All fields are required."
      },
      "typeVersion": 2.5
    },
    {
      "id": "2dace547-f410-4302-b297-e4a97da90ca8",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1664,
        -688
      ],
      "parameters": {
        "width": 672,
        "height": 672,
        "content": "## Mortgage Lead Automation with AI and Human Approval\n\nThis workflow automates mortgage lead handling while keeping you in control.\n\nNew leads are captured and normalized. High income leads are sent to Telegram for approval before any outreach happens. Once approved, an AI generated email draft is created in Gmail and a dedicated Google Drive folder is provisioned.\n\nThe client receives a secure upload link to submit ID, payslip, and bank statement. Documents are validated, stored automatically, and logged in Supabase. You receive real time notifications for success or partial failures.\n\nThis template reduces admin time, prevents accidental outreach, and creates a structured document collection pipeline.\n\n## How it works\n1. Capture and normalize lead\n2. Apply income filter\n3. Request Telegram approval\n4. Draft AI email and create Drive folder\n5. Collect and validate documents\n6. Log results and notify broker\n\n## Setup steps\n1. Connect Gmail, Drive, Telegram, Supabase, Gemini\n2. Update Telegram chat ID\n3. Update Drive parent folder ID\n4. Adjust income threshold\n5. Test approval and upload flows"
      },
      "typeVersion": 1
    },
    {
      "id": "65fe3dc5-87d2-4692-9868-bf03951b5343",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -848,
        -736
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 400,
        "content": "Captures new mortgage inquiries and cleans name data.\nApplies income threshold before continuing.\nPrevents low quality leads from triggering AI and admin steps."
      },
      "typeVersion": 1
    },
    {
      "id": "9d13f6ac-973f-444a-b7b7-584151496c93",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -208,
        -736
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 400,
        "content": "Sends high value leads to Telegram for review.\nBroker must approve before AI email drafting.\nDeclined leads are logged in Supabase."
      },
      "typeVersion": 1
    },
    {
      "id": "5945c161-51ef-43d4-b353-9874ed9c2ee4",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        288,
        -736
      ],
      "parameters": {
        "color": 7,
        "width": 976,
        "height": 448,
        "content": "Generates personalized mortgage email using Gemini.\nCreates client specific Drive folder.\nPrepares Gmail draft with secure upload link."
      },
      "typeVersion": 1
    },
    {
      "id": "c618560b-ffeb-45eb-8696-c37c985c0786",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 576,
        "content": "Client uploads required documents through secure form.\nHidden fields link uploads to correct Drive folder.\nInput validation ensures required data is present."
      },
      "typeVersion": 1
    },
    {
      "id": "5dbbeca7-b331-4a06-b155-2c3f16e6757f",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -176,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 320,
        "content": "Uploads ID, payslip, and bank statement to Drive.\nHandles partial failures without breaking workflow.\nEvaluates overall upload status."
      },
      "typeVersion": 1
    },
    {
      "id": "f49871a9-702e-4707-9c71-ec3c0a66b133",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        464,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 608,
        "content": "Sends Telegram notifications for success or failure.\nAggregates errors and activity data.\nStores structured results in Supabase."
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "Upload ID1": {
      "main": [
        [
          {
            "node": "Upload Payslip1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Input": {
      "main": [
        [
          {
            "node": "Upload ID1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Validation Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Payslip1": {
      "main": [
        [
          {
            "node": "Upload Bank Statement1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log declined lead": {
      "main": [
        []
      ]
    },
    "Store in Database": {
      "main": [
        []
      ]
    },
    "Aggregate Log Data": {
      "main": [
        [
          {
            "node": "Store in Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Gmail Draft": {
      "main": [
        [
          {
            "node": "Send Email Created Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Normalize lead name",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Share Drive Folder": {
      "main": [
        [
          {
            "node": "Create Gmail Draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Drive Folder": {
      "main": [
        [
          {
            "node": "Share Drive Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize lead name": {
      "main": [
        [
          {
            "node": "Check income threshold",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload portal trigger": {
      "main": [
        [
          {
            "node": "Validate Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check income threshold": {
      "main": [
        [
          {
            "node": "Request Email Approval1",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Upload Bank Statement1": {
      "main": [
        [
          {
            "node": "Evaluate upload results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check approval response": {
      "main": [
        [
          {
            "node": "Generate Personalized Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log declined lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate upload results": {
      "main": [
        [
          {
            "node": "Check all uploads successful",
            "type": "main",
            "index": 0
          },
          {
            "node": "Update upload error log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Request Email Approval1": {
      "main": [
        [
          {
            "node": "Check approval response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update upload error log": {
      "main": [
        []
      ]
    },
    "Generate Personalized Email": {
      "main": [
        [
          {
            "node": "Create Drive Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check all uploads successful": {
      "main": [
        [
          {
            "node": "Send Success Notification",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Partial Failure Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Email Created Confirmation": {
      "main": [
        [
          {
            "node": "Aggregate Log Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}