{
  "id": "l1ojAUoUcm8l975s",
  "name": "Request and manage supplier quotes with automation",
  "tags": [],
  "nodes": [
    {
      "id": "8884e1ed-76a1-46b6-936c-e3e28da125a3",
      "name": "No Operation, do nothing1",
      "type": "n8n-nodes-base.noOp",
      "position": [
        400,
        -80
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "3592e269-6faf-4d02-b08c-7477fcebff7c",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -80,
        672
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "f02df9a1-5d0c-47d4-88ce-44937c8cee54",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1344,
        -672
      ],
      "parameters": {
        "color": 3,
        "width": 400,
        "height": 80,
        "content": "### WORKFLOW 2: RESPONSE MONITORING"
      },
      "typeVersion": 1
    },
    {
      "id": "0d656144-eeb2-4ac8-a412-61f5f92da354",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1360,
        -272
      ],
      "parameters": {
        "color": 2,
        "width": 336,
        "height": 80,
        "content": "### WORKFLOW 3: AI PRICE EXTRACTION"
      },
      "typeVersion": 1
    },
    {
      "id": "e8cbd10e-a3c4-4788-bf76-bd5c20f8aa77",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1408,
        416
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 80,
        "content": "### WORKFLOW 4: WHATSAPP FOLLOW-UPS"
      },
      "typeVersion": 1
    },
    {
      "id": "fd47901f-4c62-4289-b8e9-98fd38bbdd95",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2800,
        -576
      ],
      "parameters": {
        "width": 928,
        "height": 688,
        "content": "### Overview\nEliminate 90% of manual work in procurement by automating quote requests, response tracking, price extraction, and supplier follow-ups. \n\n### How it works\nThis workflow contains 4 independent automation modules that work together:\n Workflow 1: Quote Request Sender\nWorkflow 2: Response Monitor \nWorkflow 3: AI Price Extraction\nWorkflow 4: WhatsApp Follow-ups\n\n### How to set up\n#### 1. Create Google Sheets\nCreate \"Supplier_list\" sheet with columns: supplier_name | supplier_email | category | request_date | status | quote_received | phone_number | last_follow_up | follow_up_count\nCreate \"Price Comparison\" sheet with columns: supplier_name | supplier_email | product_name | price | currency | quantity | extracted_date | source_file\nShare both sheets or enable API access\n\n#### 2. Connect API Credentials\nGmail OAuth: For sending/receiving emails (both Quote Sender and Response Monitor modules)\nGoogle Sheets OAuth: Use same account as Gmail (all modules)\nOpenAI API key: For AI price extraction (Module 3)\nTwilio Account: SID + Auth Token for WhatsApp (Module 4)\n\n#### 3. Configure Workflow\nUpdate all Google Sheet IDs in every Google Sheets node\nConfigure Gmail credentials on all Gmail nodes \nAdd OpenAI API key to HTTP Request node or Information Extractor\nConfigure Twilio credentials and join WhatsApp sandbox\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d6143e93-6ac1-4c9e-8991-6bec49c53640",
      "name": "Reach out to suppliers",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1008,
        -944
      ],
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "message": "=<html>\n<body>\n<p>Dear {{ $json.name }},</p>\n\n<p>We hope this email finds you well.</p>\n\n<p>We would like to request a price quote for the following category: <strong>{{ $json.category }}</strong></p>\n\n<p><strong>Required Information:</strong></p>\n<ul>\n  <li>Current price list</li>\n  <li>Bulk pricing discounts (if applicable)</li>\n  <li>Lead time</li>\n  <li>Payment terms</li>\n</ul>\n\n<p>Please send your quote by <strong>{{ $now.plus(7, 'days').toFormat('yyyy-MM-dd') }}</strong></p>\n\n<p>You can reply to this email with your price list attached (PDF or Excel format).</p>\n\n<p>Best regards,<br>\nProcurement Team</p>\n</body>\n</html>",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Price Quote Request - {{ $json.category }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "c48717c0-b4d1-4eed-a325-a06749505667",
      "name": "Save to Price Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        48,
        -208
      ],
      "parameters": {
        "columns": {
          "value": {
            "notes": "={{ $json.notes }}",
            "price": "={{ $json.price }}",
            "category": "={{ $json.category }}",
            "currency": "={{ $json.currency }}",
            "quantity": "={{ $json.quantity }}",
            "source_file": "={{ $json.source_file }}",
            "product_name": "={{ $json.product_name }}",
            "supplier_name": "={{ $json.supplier_name }}",
            "extracted_date": "={{ $json.extracted_date }}",
            "supplier_email": "={{ $json.supplier_email }}"
          },
          "schema": [
            {
              "id": "supplier_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "supplier_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "supplier_email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "supplier_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "product_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "product_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "price",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "quantity",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "quantity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "notes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "extracted_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "extracted_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "source_file",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "source_file",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xHbz1EZQlnhjqP0sZFXEIVjo_Jqs4_PHbBMeeyjPVyk/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1xHbz1EZQlnhjqP0sZFXEIVjo_Jqs4_PHbBMeeyjPVyk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xHbz1EZQlnhjqP0sZFXEIVjo_Jqs4_PHbBMeeyjPVyk/edit?usp=drivesdk",
          "cachedResultName": "Price Comparison Sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "66cdab4d-7126-4865-a6bc-a26dae655e7b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        240
      ],
      "parameters": {
        "color": 5,
        "width": 256,
        "height": 432,
        "content": "#### Configure Twilio WhatsApp Sandbox\n\nGo to Twilio Console \u2192 Messaging \u2192 Try it out \u2192 WhatsApp\nSend the join code from your phone (e.g., \"join happy-elephant\")\nCopy your sandbox number (e.g., +1 415 523 8886)\nUpdate \"From\" number in Send WhatsApp node\n"
      },
      "typeVersion": 1
    },
    {
      "id": "47bd8e53-a970-4d0f-a350-64d7b36c2197",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        -240
      ],
      "parameters": {
        "color": 4,
        "width": 320,
        "height": 464,
        "content": "### Extract information from downloaded Pdf attachment\n\nObtain your API from https://platform.openai.com and connect your credentials"
      },
      "typeVersion": 1
    },
    {
      "id": "c4a6eb32-9b12-4db7-b982-f790ee1a30b7",
      "name": "Information Extractor",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        -512,
        -80
      ],
      "parameters": {
        "text": "={{ $json.document_text }}",
        "options": {
          "systemPromptTemplate": "You are an expert extraction algorithm.\nOnly extract relevant information from the text.\nIf you do not know the value of an attribute asked to extract, you may omit the attribute's value."
        },
        "attributes": {
          "attributes": [
            {
              "name": "Invoice Number",
              "required": true,
              "description": "The Number of the Invoice"
            },
            {
              "name": "Client Name",
              "required": true,
              "description": "Name of the client"
            },
            {
              "name": "Client Email",
              "required": true,
              "description": "Email address of the client"
            },
            {
              "name": "Total Amount",
              "required": true,
              "description": "Total Amount Due in the Invoice"
            },
            {
              "name": "Invoice Date",
              "required": true,
              "description": "Date of the Invoice"
            },
            {
              "name": "Due Date",
              "description": "Date with the invoice is due"
            },
            {
              "name": "Products List",
              "required": true,
              "description": "Extract ALL products as a JSON string. Format: [{\"product_name\": \"name\", \"price\": 100, \"quantity\": \"1 unit\", \"currency\": \"NGN\"}]"
            },
            {
              "name": "supplier_phone",
              "required": true,
              "description": "Extract the supplier's phone number from the document. Look for phone, mobile, or contact number"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "37a01b6c-1040-4e55-b5e9-6f457e50ccf0",
      "name": "Execute workflow",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1584,
        -944
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e38ca5d0-59a7-40c6-9275-ee134c237c63",
      "name": "Trigger workflow every hour",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1712,
        -432
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "a8ae81e6-f54c-4a21-b72c-1cb4c76cc1f3",
      "name": "Trigger workflow daily",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1760,
        -80
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "158cd842-3cc3-4422-9221-ae67195ecb84",
      "name": "Trigger workflow daily1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1760,
        720
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7dc4af35-2112-4499-a9fb-ba760329f1e7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1408,
        -1088
      ],
      "parameters": {
        "width": 288,
        "height": 352,
        "content": "\nCode in JavaScript hardcodes the details of the suppliers. This can however be customized by changing the node to fetch the details from different sources."
      },
      "typeVersion": 1
    },
    {
      "id": "2820ea83-a045-4f41-a675-6d3e387e1661",
      "name": "Hardcode suppliers details",
      "type": "n8n-nodes-base.code",
      "position": [
        -1344,
        -944
      ],
      "parameters": {
        "jsCode": "const suppliers = [\n  { name: \"ABC Electronics\", email: \"user@example.com\", category: \"Electronics\" },\n  { name: \"XYZ Hardware\", email: \"user@example.com\", category: \"Hardware\" },\n  { name: \"Tech Solutions\", email: \"user@example.com\", category: \"Software\" }\n];\n\nreturn suppliers.map(s => ({ json: s }));"
      },
      "typeVersion": 2
    },
    {
      "id": "5e86a720-a02d-4fb7-9ef2-5d2b2e706eb8",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1024,
        -1056
      ],
      "parameters": {
        "color": 4,
        "width": 368,
        "height": 320,
        "content": "Reach out to suppliers and log details of suppliers to supplier_list sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "6b4e3235-f004-4cfc-91c8-eef21ce76112",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1520,
        -528
      ],
      "parameters": {
        "color": 2,
        "width": 544,
        "content": "Searches mail for responses from suppliers ever hour, if there is a response, node 2 extracts the response, parses the mail and looks out for an attachment."
      },
      "typeVersion": 1
    },
    {
      "id": "675416b6-adc4-4152-be2d-ec28d44986db",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        -544
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "content": "If mail has attachment, the true branch returns an out put which is then used to update the quotes_received, follow-up needed and status columns in the supplier sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "554eacd4-e42b-4c35-8e26-c19ef85150e3",
      "name": "Log to suppliers sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -752,
        -944
      ],
      "parameters": {
        "columns": {
          "value": {
            "category": "={{ $('Hardcode suppliers details').item.json.category }}",
            "request_date": "={{ $now.toFormat('yyyy-MM-dd') }}",
            "supplier_name": "={{ $('Hardcode suppliers details').item.json.name }}",
            "supplier_email": "={{ $('Hardcode suppliers details').item.json.email }}",
            "follow_up_needed": "Yes"
          },
          "schema": [
            {
              "id": "supplier_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "supplier_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "supplier_email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "supplier_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "request_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "request_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "quote_received",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "quote_received",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_needed",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "follow_up_needed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone_number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "phone_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_follow_up",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "last_follow_up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "follow_up_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit?usp=drivesdk",
          "cachedResultName": "Supplier_sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "87bca557-d7df-4aa0-8647-e80980130330",
      "name": "Search for quote replies",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1504,
        -432
      ],
      "parameters": {
        "filters": {
          "q": "subject:(Price Quote Request OR Re: Price Quote Request) newer_than:7d has:attachment",
          "labelIds": [
            "INBOX"
          ]
        },
        "operation": "getAll"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "68fd9337-3979-4c75-9e99-f6d55816f6a9",
      "name": "Get email details",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1312,
        -432
      ],
      "parameters": {
        "simple": false,
        "options": {
          "downloadAttachments": false
        },
        "messageId": "={{ $json.id }}",
        "operation": "get"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "45bed9fe-964f-48bc-9f56-5566da53e353",
      "name": "Parse email data",
      "type": "n8n-nodes-base.code",
      "position": [
        -1104,
        -432
      ],
      "parameters": {
        "jsCode": "// Gmail already parsed the data for us!\nconst fromEmail = $json.from?.value?.[0]?.address || 'user@example.com';\nconst toEmail = $json.to?.value?.[0]?.address || '';\nconst subject = $json.subject || 'No Subject';\n\n// Check if this is a reply to our supplier email (the +supplier emails)\nconst supplierEmail = toEmail.includes('+supplier') ? toEmail : fromEmail;\n\n// Attachments are in binary data (we'll handle in next node)\n// For now, just check if email likely has attachments\nconst hasAttachments = $json.text?.includes('attached') || $json.html?.includes('attached');\n\nreturn [{\n  json: {\n    messageId: $json.id,\n    supplierEmail: supplierEmail,\n    fromEmail: fromEmail,\n    subject: subject,\n    receivedDate: new Date().toISOString().split('T')[0],\n    emailText: $json.text,\n    hasAttachments: hasAttachments\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "1fb50326-40a3-4595-a690-f50e442a02f6",
      "name": "Has attachments?",
      "type": "n8n-nodes-base.if",
      "position": [
        -912,
        -432
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.hasAttachments }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "64e6f57b-2b93-420f-9fb0-aed4bd1a1d00",
      "name": "Update supplier sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -640,
        -448
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "Quote Received",
            "quote_received": "Yes",
            "supplier_email": "={{$json.supplierEmail }}",
            "follow_up_needed": "No"
          },
          "schema": [
            {
              "id": "supplier_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "supplier_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "supplier_email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "supplier_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "request_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "request_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "quote_received",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "quote_received",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_needed",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "follow_up_needed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone_number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "phone_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_follow_up",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "last_follow_up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "follow_up_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "supplier_email"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit?usp=drivesdk",
          "cachedResultName": "Supplier_sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "ac3e5c25-5512-498f-9b05-1c4f324f2616",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1632,
        -176
      ],
      "parameters": {
        "width": 624,
        "content": "This reads the 'quote received' column of the supplier_list sheet, and outputs the row(s) of the suppliers who has sent their quotes. the Get Supplier node then gets the email using the mail of the supplier gotten from the previous node, and the next node proceeds to download the attachment from that mail."
      },
      "typeVersion": 1
    },
    {
      "id": "afac5d7c-7381-4d7f-afdf-b2f4fde2eef4",
      "name": "Get quotes to process",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1552,
        -80
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "Yes",
              "lookupColumn": "quote_received"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit?usp=drivesdk",
          "cachedResultName": "Supplier_sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "95704505-e499-488c-8e4e-8e36af32a19f",
      "name": "Get supplier email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1344,
        -80
      ],
      "parameters": {
        "limit": 10,
        "filters": {
          "q": "subject:\"Price Quote Request\" has:attachment newer_than:7d"
        },
        "operation": "getAll"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "ec168287-7299-4aea-bb5d-d32c6f75dc44",
      "name": "Download all attachments",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1136,
        -80
      ],
      "parameters": {
        "simple": false,
        "options": {
          "downloadAttachments": true
        },
        "messageId": "={{ $json.id }}",
        "operation": "get"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "05bea877-4305-48f7-8429-ee78c94723c1",
      "name": "Extract from file",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -928,
        -80
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "={{ Object.keys($binary)[0] }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "f418f63b-9653-45ea-877b-5db38c7db85c",
      "name": "Prepare for openAI",
      "type": "n8n-nodes-base.code",
      "position": [
        -720,
        -80
      ],
      "parameters": {
        "jsCode": "// Collect extracted text from all PDF items\nconst items = $input.all();\n\nconst extractedText = items\n  .map(item => item.json.text || item.json.data || '')\n  .filter(t => t.trim() !== '')\n  .join('\\n\\n---\\n\\n');\n\n// Get supplier info safely\nconst quotesData = $('Get quotes to process').all();\nconst supplierData = quotesData.length > 0 ? quotesData[0].json : {};\n\nif (!extractedText) {\n  return [{\n    json: {\n      error: 'No extracted text found',\n      debug_sample: items[0]?.json || {}\n    }\n  }];\n}\n\nreturn [{\n  json: {\n    supplier_name: supplierData.supplier_name || 'Unknown Supplier',\n    supplier_email: supplierData.supplier_email || 'user@example.com',\n    category: supplierData.category || 'Unknown',\n    document_text: extractedText\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "e4b02c68-6592-4bb4-b8cb-e6d6e95dc896",
      "name": "Extract key information from invoice",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -416,
        112
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "bc888fa7-17f3-496c-8030-17d0e6c19260",
      "name": "Parse model output ",
      "type": "n8n-nodes-base.code",
      "position": [
        -160,
        -80
      ],
      "parameters": {
        "jsCode": "// Get the products string from Information Extractor\nconst productsString = $input.first().json.output['Products List'] || '[]';\n\n// Parse the JSON string\nlet products = [];\ntry {\n  products = JSON.parse(productsString);\n} catch (error) {\n  return [{\n    json: {\n      error: 'Failed to parse products',\n      raw_string: productsString\n    }\n  }];\n}\n\n// Get supplier info\nconst supplierData = $('Prepare for openAI').first().json;\n\n\n\n// Create one row per product\nreturn products.map(product => ({\n  json: {\n    supplier_name: supplierData.supplier_name,\n    supplier_email: supplierData.supplier_email,\n    category: supplierData.category,\n    product_name: product.product_name,\n    price: parseFloat(product.price) || 0,\n    currency: product.currency || 'NGN',\n    quantity: product.quantity || '1',\n    notes: product.notes || '',\n    source_file: supplierData.file_name || 'unknown',\n    supplier_phone: $input.first().json.output['supplier_phone'] || '',\n    extracted_date: new Date().toISOString().split('T')[0],\n\n  }\n}));\n\n"
      },
      "typeVersion": 2
    },
    {
      "id": "66c358cf-5a26-4dfc-b829-7c4f17d1d66e",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -192,
        -320
      ],
      "parameters": {
        "width": 448,
        "height": 560,
        "content": "Parses extracted output to a valid json format, then updates the 'price comparison' sheet. \n\nAlso updates the supplier_list sheet with the phone number extracted from invoice for record keeping"
      },
      "typeVersion": 1
    },
    {
      "id": "35e26efe-8357-4905-bafc-247be7fe50de",
      "name": "Update supplier sheet with phone number",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        64,
        64
      ],
      "parameters": {
        "columns": {
          "value": {
            "phone_number": "={{ $json.supplier_phone }}",
            "supplier_email": "={{ $json.supplier_email }}"
          },
          "schema": [
            {
              "id": "supplier_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "supplier_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "supplier_email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "supplier_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "request_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "request_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "quote_received",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "quote_received",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_needed",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "follow_up_needed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone_number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "phone_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_follow_up",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "last_follow_up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "follow_up_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "supplier_email"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit?usp=drivesdk",
          "cachedResultName": "Supplier_sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "f15c3136-0a6a-4f35-ba5d-e98e1274ef04",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1600,
        592
      ],
      "parameters": {
        "color": 5,
        "width": 624,
        "height": 208,
        "content": "Searches the supplier_list sheet to get a list of suppliers who needs a reminder to send their quote. If a follow up is needed, the true branch of the follow up node returns an output."
      },
      "typeVersion": 1
    },
    {
      "id": "38db00a6-6879-457a-add8-454c0922ff52",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -912,
        512
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 336,
        "content": "A customized message is prepared and sent to suppliers through to phone numbers or their email address if no phone number."
      },
      "typeVersion": 1
    },
    {
      "id": "9953a097-591d-4969-aea8-a4b3230bdaf0",
      "name": "Prepare message",
      "type": "n8n-nodes-base.code",
      "position": [
        -896,
        704
      ],
      "parameters": {
        "jsCode": "// Process ALL suppliers that need follow-up\nconst suppliers = $input.all().map(item => item.json);\n\nreturn suppliers.map(supplier => {\n  const requestDate = new Date(supplier.request_date || supplier.request_sent_date);\n  const daysSince = Math.floor((new Date() - requestDate) / (1000 * 60 * 60 * 24));\n  \n  // Create personalized message\n  let message = `Hi ${supplier.supplier_name},\\n\\n`;\n  \n  if (daysSince === 3) {\n    message += `This is a friendly reminder about the price quote we requested ${daysSince} days ago for ${supplier.category}.\\n\\n`;\n    message += `Could you please send us your pricing when you get a chance?\\n\\n`;\n  } else if (daysSince === 5) {\n    message += `Following up on our price quote request from ${daysSince} days ago.\\n\\n`;\n    message += `We'd appreciate receiving your quote soon as we're comparing options.\\n\\n`;\n  } else if (daysSince >= 7) {\n    message += `Final reminder: We requested a quote ${daysSince} days ago for ${supplier.category}.\\n\\n`;\n    message += `Please let us know if you're able to provide pricing.\\n\\n`;\n  }\n  \n  message += `Category: ${supplier.category}\\n`;\n  message += `Original Request: ${requestDate.toLocaleDateString()}\\n\\n`;\n  message += `Thank you!\\nProcurement Team`;\n  \n  // Format phone number\n  let phoneNumber = supplier.phone_number || '';\n  if (phoneNumber && !phoneNumber.startsWith('+')) {\n    phoneNumber = '+' + phoneNumber;\n  }\n  \n  return {\n    json: {\n      supplier_name: supplier.supplier_name,\n      supplier_email: supplier.supplier_email,\n      phone_number: phoneNumber,\n      message: message,\n      days_since_request: daysSince,\n      follow_up_type: daysSince === 3 ? 'First Reminder' : daysSince === 5 ? 'Second Reminder' : 'Final Reminder',\n      follow_up_count: supplier.follow_up_count || 0\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "48088f7d-6ffa-427e-9703-13af427a2e5a",
      "name": "Has phone number?",
      "type": "n8n-nodes-base.if",
      "position": [
        -720,
        656
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "a8108698-d4d2-4c1d-81b1-f12c3000e36c",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.phone_number }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "34154208-d4f2-411f-bac9-91927d5b4822",
      "name": "Send follow-up mail",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -496,
        816
      ],
      "parameters": {
        "sendTo": "={{ $json.supplier_email }}",
        "message": "={{ $json.message }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Follow-up: Price Quote Request -  {{ $json.supplier_name }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "f0cffc9e-8fd1-4d49-a008-3d6a82b3b97c",
      "name": "Update follow up count in supplier sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -288,
        672
      ],
      "parameters": {
        "columns": {
          "value": {
            "last_follow_up": "={{ $now.toFormat('yyyy-MM-dd') }}",
            "supplier_email": "={{ $('Prepare message').item.json.supplier_email }}",
            "follow_up_count": "={{ parseInt($json.follow_up_count || 0) + 1 }}",
            "follow_up_needed": "No"
          },
          "schema": [
            {
              "id": "supplier_name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "supplier_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "supplier_email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "supplier_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "request_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "request_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "quote_received",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "quote_received",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_needed",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "follow_up_needed",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone_number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "phone_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_follow_up",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_follow_up",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "follow_up_count",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "follow_up_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "supplier_email"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit?usp=drivesdk",
          "cachedResultName": "Supplier_sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "99933e9c-5b6c-43a3-a487-5d67e086573b",
      "name": "Any follow-ups needed?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1120,
        720
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.length }}",
              "value2": 0,
              "operation": "larger"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "df549c40-cced-411d-923e-4d34b0bbc765",
      "name": "Filter pending quotes",
      "type": "n8n-nodes-base.code",
      "position": [
        -1328,
        720
      ],
      "parameters": {
        "jsCode": "// Check which quotes need follow-up\nconst today = new Date();\nconst quotes = $input.all().map(item => item.json);\n\nconst needFollowUp = quotes.filter(quote => {\n  // Skip if already received\n  if (quote.quote_received === 'Yes') {\n    return false;\n  }\n  \n  // Calculate days since request\n  const requestDate = new Date(quote.request_date || quote.request_sent_date);\n  const daysSince = Math.floor((today - requestDate) / (1000 * 60 * 60 * 24));\n  \n  // Follow up after 3 days, then 5 days, then 7 days\n  const shouldFollowUp = daysSince === 3 || daysSince === 5 || daysSince === 7;\n  \n  return shouldFollowUp;\n});\n\nreturn needFollowUp.map(quote => ({ json: quote }));"
      },
      "typeVersion": 2
    },
    {
      "id": "0b0e3c85-e225-4480-b327-297e9c269e54",
      "name": "Get all quotes",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1536,
        720
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1xrurRmmG-RRXdDLVuVjE3T_7l1xP1CFq10t2E5uIwF8/edit?usp=drivesdk",
          "cachedResultName": "Supplier_sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "95d43639-452f-4ab6-9b0b-bea44864acfe",
      "name": "Send WhatsApp follow-up message",
      "type": "n8n-nodes-base.twilio",
      "position": [
        -496,
        496
      ],
      "parameters": {
        "to": "={{ $json.phone_number }}",
        "from": "+1234567890",
        "message": "={{ $json.message }}",
        "options": {},
        "toWhatsapp": true
      },
      "credentials": {
        "twilioApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "d95bbeb3-ab89-4fb1-8ff0-0972e6458e8f",
  "connections": {
    "Get all quotes": {
      "main": [
        [
          {
            "node": "Filter pending quotes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare message": {
      "main": [
        [
          {
            "node": "Has phone number?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute workflow": {
      "main": [
        [
          {
            "node": "Hardcode suppliers details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has attachments?": {
      "main": [
        [
          {
            "node": "Update supplier sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse email data": {
      "main": [
        [
          {
            "node": "Has attachments?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from file": {
      "main": [
        [
          {
            "node": "Prepare for openAI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get email details": {
      "main": [
        [
          {
            "node": "Parse email data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has phone number?": {
      "main": [
        [
          {
            "node": "Send WhatsApp follow-up message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send follow-up mail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get supplier email": {
      "main": [
        [
          {
            "node": "Download all attachments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare for openAI": {
      "main": [
        [
          {
            "node": "Information Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse model output ": {
      "main": [
        [
          {
            "node": "Update supplier sheet with phone number",
            "type": "main",
            "index": 0
          },
          {
            "node": "Save to Price Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Price Sheet": {
      "main": [
        [
          {
            "node": "No Operation, do nothing1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send follow-up mail": {
      "main": [
        [
          {
            "node": "Update follow up count in supplier sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter pending quotes": {
      "main": [
        [
          {
            "node": "Any follow-ups needed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get quotes to process": {
      "main": [
        [
          {
            "node": "Get supplier email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Information Extractor": {
      "main": [
        [
          {
            "node": "Parse model output ",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any follow-ups needed?": {
      "main": [
        [
          {
            "node": "Prepare message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reach out to suppliers": {
      "main": [
        [
          {
            "node": "Log to suppliers sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger workflow daily": {
      "main": [
        [
          {
            "node": "Get quotes to process",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger workflow daily1": {
      "main": [
        [
          {
            "node": "Get all quotes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download all attachments": {
      "main": [
        [
          {
            "node": "Extract from file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search for quote replies": {
      "main": [
        [
          {
            "node": "Get email details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hardcode suppliers details": {
      "main": [
        [
          {
            "node": "Reach out to suppliers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger workflow every hour": {
      "main": [
        [
          {
            "node": "Search for quote replies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send WhatsApp follow-up message": {
      "main": [
        [
          {
            "node": "Update follow up count in supplier sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract key information from invoice": {
      "ai_languageModel": [
        [
          {
            "node": "Information Extractor",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Update follow up count in supplier sheet": {
      "main": [
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}