{
  "id": "QiEoooyNMeJcvKKg",
  "name": "Automating WhatsApp replies in Go High Level with Redis and Anthropic",
  "tags": [
    {
      "id": "PnRGSMhEDCtkgPVA",
      "name": "OJAUUMDev",
      "createdAt": "2025-07-21T20:12:28.081Z",
      "updatedAt": "2025-07-21T20:12:28.081Z"
    }
  ],
  "nodes": [
    {
      "id": "6290c10a-80ac-46b8-9d49-dcf5dff98125",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1380,
        320
      ],
      "parameters": {
        "path": "fce352e8-8edf-447c-9b54-c2c2b6649ccc",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "4f19d6b1-829c-4824-8e75-e0781caa59f3",
      "name": "Switch1",
      "type": "n8n-nodes-base.switch",
      "position": [
        -1220,
        320
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "436fa76a-f948-4de3-86a1-9ed6e568430f",
                    "operator": {
                      "type": "string",
                      "operation": "notContains"
                    },
                    "leftValue": "={{ $json.body.message.body }}",
                    "rightValue": "type message: audio"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "a4574272-ebee-40a4-a1fb-9139e5f6112e",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    },
                    "leftValue": "={{ $json.body.message.body }}",
                    "rightValue": "type message: audio"
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "2f44dc60-d93f-4ee0-8c5a-e481541d6486",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        460,
        160
      ],
      "parameters": {
        "text": "={{ $('messages').first().json.menssage }}",
        "options": {
          "systemMessage": "=# Summary\n\nYou are the customer service assistant for **GlobalPoint Services**. Your task is to answer user questions **only using the information provided by the `ClientInfo` tool**, which contains accurate data about services, branches, locations, schedules, prices, and requirements.\n\n# Tools\n\n**ClientInfo** \u2192 Use this tool to obtain the exact information. Its content consists of a list of objects under the `\"response\"` field with the following structure:\n\n```json\n{\n  \"response\": {\n    \"Category\": \"Consulting\",\n    \"Service\": \"Business Strategy Session\",\n    \"Requirements\": \"Schedule at least 48 hours in advance\",\n    \"Price (USD)\": 150\n  }\n},\n{\n  \"response\": {\n    \"Branch\": \"GlobalPoint Downtown Office\",\n    \"Location\": \"123 Main Street, Downtown, Springfield, USA\",\n    \"Schedule\": \"Mon\u2013Fri: 9 a.m.\u20136 p.m.; Sat: 9 a.m.\u20131 p.m.; Sun: Closed\",\n    \"Notes\": \"Walk-ins are welcome during business hours.\"\n  }\n}\n```\n\n# Rules\n\n* When a user asks about branches, locations, schedules, services, prices, or requirements, **always use ClientInfo to find exact matches**, regardless of case sensitivity or minor typos.\n* You may accept partial matches or synonyms as long as they clearly refer to the exact service or branch listed in ClientInfo.\n* Always respond using the exact service or branch name **as it appears in ClientInfo**, and clarify:\n  `The price for \"[exact name]\" is XX USD.`\n  or\n  `The branch \"[exact name]\" is located at [exact location]. Schedule: [schedule].`\n* **Never provide information that is not explicitly included in ClientInfo.**\n* If no clear match is found, respond with:\n  `Sorry, we do not offer that service or have that branch in our records. Is there anything else I can help you with?`\n* Use a **friendly, clear, simple, and helpful** tone, always in the **same language as the user**.\n* If the question is generic or just a greeting, respond politely and invite them to ask.\n\n# Examples\n\n**1. Input:** Hello\n**Response:** Hi! Welcome to GlobalPoint Services. How can I assist you today?\n\n**2. Input:** I have a question\n**Response:** Sure, tell me more so I can help.\n\n**3. Input:** What services do you offer?\n**Action:** Read all items in ClientInfo.\n**Response:** At GlobalPoint Services, we offer options such as \\[brief list based on Category and Service].\n\n**4. Input:** How much is the Business Strategy Session?\n**Action:** Search \"Business Strategy Session\" in ClientInfo.\n**Response:** The price for the service \"Business Strategy Session\" is 150 USD. Requirements: Schedule at least 48 hours in advance.\n\n**5. Input:** Where is the Downtown Office?\n**Action:** Search \"Downtown Office\" in branches within ClientInfo.\n**Response:** Our branch \"GlobalPoint Downtown Office\" is located at 123 Main Street, Downtown, Springfield, USA. Schedule: Mon\u2013Fri: 9 a.m.\u20136 p.m. and Sat: 9 a.m.\u20131 p.m.\n\n# Final Reminders\n\n* **Never make up data, prices, or addresses.**\n* **Never answer from general knowledge**, only from ClientInfo.\n* **Always use the exact service or branch name when giving prices or requirements.**\n* **Do not give suggestions or recommendations not present in the data.**\n\n"
        },
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "e60eaf2a-9c68-49bf-b237-d0bbd6bdd1c7",
      "name": "Anthropic Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        380,
        380
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-20250514",
          "cachedResultName": "Claude Sonnet 4"
        },
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "a29f6bab-4088-48f2-802a-c59f44d0d3f5",
      "name": "Update Contact",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1280,
        160
      ],
      "parameters": {
        "url": "=https://rest.gohighlevel.com/v1/contacts/{{ $('Webhook').item.json.body.contact_id }}",
        "method": "PUT",
        "options": {},
        "jsonBody": "={\n  \"customField\": {\n    \"{{ $json.customFields.find(field => field.name === 'IA_answer').id }}\": \"{{ $('Sanitize and Format Message Output').item.json.output }}\"\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {}
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ba1cfe67-f7ce-4f32-82a9-99557f4b6495",
      "name": "GHL Custom fields",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1080,
        160
      ],
      "parameters": {
        "url": "https://rest.gohighlevel.com/v1/custom-fields/",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "5ab4f7b8-ccf3-440b-a9ea-54e6d5e595f7",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        -500,
        220
      ],
      "parameters": {
        "amount": 15
      },
      "typeVersion": 1.1
    },
    {
      "id": "b081b133-b582-447e-bf52-8647d4c18e24",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        -180,
        220
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "41b0355b-7204-4e25-b74a-7bf70dea8a9c",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.messages.last() }}",
              "rightValue": "={{ $('Sanitize and Format Message Body').item.json.text }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1f6b0707-cd9d-4d93-ba39-757348beceb1",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -20,
        380
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "86cb66f8-0d79-40ee-88c6-48ac440a08cf",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        520,
        380
      ],
      "parameters": {
        "sessionKey": "={{ $('Webhook').item.json.body.phone }}",
        "sessionIdType": "customKey"
      },
      "typeVersion": 1.3
    },
    {
      "id": "27d0db94-0317-423f-8b58-8178211f8dfb",
      "name": "Save message",
      "type": "n8n-nodes-base.redis",
      "position": [
        -660,
        220
      ],
      "parameters": {
        "list": "={{ $('Webhook').item.json.body.contact_id }}",
        "tail": true,
        "operation": "push",
        "messageData": "={{ $json.text }}"
      },
      "typeVersion": 1
    },
    {
      "id": "6c8b6cb0-7cd7-4e3d-90c4-4e117f3449eb",
      "name": "Get messages",
      "type": "n8n-nodes-base.redis",
      "position": [
        -340,
        220
      ],
      "parameters": {
        "key": "={{ $('Webhook').item.json.body.contact_id }}",
        "options": {},
        "operation": "get",
        "propertyName": "mensajes"
      },
      "typeVersion": 1
    },
    {
      "id": "877a16b7-b461-439f-8501-9a4c418dc7d0",
      "name": "Sanitize and Format Message Body",
      "type": "n8n-nodes-base.code",
      "position": [
        -940,
        220
      ],
      "parameters": {
        "jsCode": "return [{\n  text: $input.first().json.body.message.body\n    .replace(/\\\\+\"/g, '\"')   // Fix incorrectly escaped double quotes\n    .replace(/\\n/g, \"\\\\n\")   // Properly escape line breaks\n    .replace(/\\r/g, \"\\\\r\")   // Escape carriage returns\n    .replace(/\\t/g, \"\\\\t\")   // Escape tab characters\n    .trim()                  // Remove unnecessary whitespace\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "8c8a0ce0-4fc3-4979-8f1a-331a0861bfe4",
      "name": "Delete messages",
      "type": "n8n-nodes-base.redis",
      "position": [
        120,
        160
      ],
      "parameters": {
        "key": "={{ $('Webhook').item.json.body.contact_id }}",
        "operation": "delete"
      },
      "typeVersion": 1
    },
    {
      "id": "55e65c69-54ec-4df1-8197-0dd0b4f6f416",
      "name": "messages",
      "type": "n8n-nodes-base.set",
      "position": [
        -20,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "7bb3ef98-b766-4ad7-8343-b2885bd70225",
              "name": "message",
              "type": "string",
              "value": "={{ $node[\"Get messages\"].json[\"messages\"].join(\"\\n\") }}"
            },
            {
              "id": "62dfc214-fb40-4a59-81a4-b01c6c0860af",
              "name": "id",
              "type": "string",
              "value": "={{ $('Webhook').item.json.body.contact_id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e65eca71-742f-4301-bbab-5130fe7e4d34",
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        -600,
        1140
      ],
      "parameters": {
        "inputSource": "passthrough"
      },
      "typeVersion": 1.1
    },
    {
      "id": "22b16984-474c-488a-b012-17d6cc8f26c9",
      "name": "Download file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -440,
        1140
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "list",
          "value": "1Im72SvVQhzjLk_rVUidGK0du4s2zMZ3H",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Im72SvVQhzjLk_rVUidGK0du4s2zMZ3H/edit?usp=drivesdk&ouid=107080324345235325088&rtpof=true&sd=true",
          "cachedResultName": "Examenes de Laboratorio Prueba Doctor Premier.xlsx"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "aabc26f2-36a2-469c-8c60-5a7b35030c16",
      "name": "Success",
      "type": "n8n-nodes-base.set",
      "position": [
        80,
        1140
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "39c2f302-03be-4464-a17a-d7cc481d6d44",
              "name": "=response",
              "type": "object",
              "value": "={{ $json }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ce02d432-ecca-44ff-ac7e-2f3d12f09185",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        -60,
        1140
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "e9836dfc-8a86-41be-ac81-5e706ce38a23",
      "name": "Call n8n Workflow Tool",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        680,
        380
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "yVUPXPNCNlo5HkJs",
          "cachedResultName": "My Sub-Workflow 1"
        },
        "workflowInputs": {
          "value": {},
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7a881605-ce1d-4ed4-9c61-36533b759286",
      "name": "Extract Tests",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -240,
        1060
      ],
      "parameters": {
        "options": {
          "sheetName": "Tests"
        },
        "operation": "xlsx"
      },
      "typeVersion": 1
    },
    {
      "id": "44d5d6c6-add6-424c-ad6c-0108435a1c1b",
      "name": "Extract Sites",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -240,
        1240
      ],
      "parameters": {
        "options": {
          "sheetName": "Sites"
        },
        "operation": "xlsx",
        "binaryPropertyName": "=data"
      },
      "typeVersion": 1
    },
    {
      "id": "b8d3874e-ee58-4da7-bcf5-3b6b67071411",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -660,
        580
      ],
      "parameters": {
        "color": 5,
        "width": 900,
        "height": 820,
        "content": "# Google Drive Excel Merge Workflow\n\nThis is an **optional example** that should be created in a **separate workflow**. It demonstrates how to extract client information from an Excel file with two sheets, `tests` and `sites`, merge the data, and return it to an LLM.\n\n## 1. Setup and Download\n* Create Google OAuth 2.0 credentials in **Google Cloud Console** and enable the **Google Drive API**.\n* Authenticate and download the specified Excel file from Google Drive.\n---\n## 2. Extract Data from Excel\n* Read the Excel file.\n* Extract data from the **tests** sheet.\n* Extract data from the **sites** sheet.\n---\n## 3. Merge the Data\n* Combine the extracted data from both sheets into one dataset.\n* Ensure formatting and structure are consistent.\n* Return the merged dataset as the response to the LLM request.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "62d3abdc-7eac-4552-a064-23097d6ea7d6",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1400,
        -300
      ],
      "parameters": {
        "width": 680,
        "height": 860,
        "content": "# GHL to n8n SMS Reply Bridge\n\n## 1. Requirements and Setup\n\n* Requires the **GoHighLevel sub-account API** (API key/token) where the chatbot will run.\n* In GoHighLevel, create an **Automation**: trigger on **Customer Replied (SMS)** and send the payload to your **n8n Webhook** URL.\n* Use the **Wazzap** plugin in GHL to receive WhatsApp replies into the same flow.\n* Cost-Saving Trick: Create a custom field in GHL, for example **IA_answer** and update with your bot\u2019s response instead of triggering extra paid automations on every inbound message.\n---\n\n## 2. Webhook and Filter\n\n* Receive the HTTP POST in **n8n Webhook**.\n* Add a filter/switch:\n  * If the message is **audio** (Wazzap/GHL does not provide a downloadable file), **do not process**. Send a personalized fallback reply asking for text.\n  * If the message is **text**, run a **Function/Code** node to **sanitize**:\n    * Fix incorrectly escaped quotes.\n    * Escape line breaks, carriage returns, and tabs.\n    * Trim whitespace and remove invalid fields.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "20e82e23-0434-495e-9676-0cf6d91f1c5a",
      "name": "Update Contact No audio",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -860,
        400
      ],
      "parameters": {
        "url": "=https://rest.gohighlevel.com/v1/contacts/{{ $('Webhook').item.json.body.contact_id }}",
        "method": "PUT",
        "options": {},
        "jsonBody": "={\n  \"customField\": {\n    \"{{ $json.customFields.find(field => field.name === 'IA_answer').id }}\": \"Sorry, I can\u2019t listen to voice notes at the moment. Could you please write your question or concern? Thank you very much.\"\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ad9f2916-0f90-4c4a-85eb-6b7dfc705fa8",
      "name": "Get GHL Custom fields",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1060,
        400
      ],
      "parameters": {
        "url": "https://rest.gohighlevel.com/v1/custom-fields/",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "1cd6d85e-62e7-41d4-a4a8-5e6ded3140de",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -660,
        -300
      ],
      "parameters": {
        "color": 6,
        "width": 900,
        "height": 860,
        "content": "# Redis Message Buffer Workflow\n\n## 1. Purpose\n* Batch multiple user messages sent within a short window and pass a single merged text to the next step.\n---\n## 2. Setup\n* Configure a Redis database and set credentials/values in the Redis nodes (host, port, db index, password).\n* Use one Redis list per contact, keyed by the `contact_id` from the Webhook.\n---\n## 3. Flow\n* **Save message**: Push the sanitized text to the Redis list for `contact_id`.\n* **Wait**: Pause for a few seconds (e.g., 15) so the user can finish typing.\n* **Get messages**: Read all items from the Redis list into `messages`.\n* **If**: Compare `messages.last()` with the latest sanitized text; if equal proceed, if not do nothing.\n* **messages**: Join all collected items with newline into `message` and keep `id = contact_id`.\n* **Delete messages**: Delete the Redis key for that `contact_id` to clear the buffer.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "6949cf34-0086-4493-b281-2d8d200c7fcb",
      "name": "Sanitize and Format Message Output",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        160
      ],
      "parameters": {
        "jsCode": "return [{\n  output: $input.first().json.output\n    .replace(/^\"{|}\"$/g, \"\") // Removes double quotes at the start and end if present\n    .replace(/^{\"response\":\\s*\"/, '') // Removes '{\"response\":\"' at the beginning if present\n    .replace(/\"}$/, '') // Removes '\"}' at the end if present\n    .replace(/\\\\\"/g, '\"') // Converts escaped quotes \\\" into normal quotes \"\n    .replace(/\\n/g, \"\\\\n\") // Escapes newlines correctly\n    .replace(/\\r/g, \"\\\\r\") // Escapes carriage returns\n    .replace(/\\t/g, \"\\\\t\") // Escapes tabs\n    .replace(/^\"+|\"+$/g, \"\") // \ud83d\udd25 New line: Removes extra double quotes at the edges\n    .replace(/\"/g, '\\\\\"') // Escapes internal double quotes for JSON\n    .trim() // Removes unnecessary whitespace\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "99f56ece-0c95-4148-938a-51e9d32d047f",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        340,
        -300
      ],
      "parameters": {
        "color": 3,
        "width": 660,
        "height": 860,
        "content": "# ClientInfo LLM Response Workflow\n\n## 1. AI Agent with ClientInfo Tool\n* Answers user questions **only** with data from **ClientInfo** (sub-workflow below), calling it through **Call n8n Workflow Tool**.\n  * Uses **Anthropic (Claude Sonnet 4)** in this example but can work with any chat model by setting the API key.\n  * The system prompt enforces answering only from ClientInfo, and can be tuned for your client\u2019s tone, style, or specificity based on available data.\n  * Keeps short conversational context with **Simple Memory** using the user\u2019s phone as the session key.\n---\n## 2. Sanitize Output\n* After generating the response, a **Function/Code** node cleans it by fixing incorrectly escaped quotes, escaping line breaks, carriage returns, and tabs, trimming whitespace, and removing invalid fields before sending it downstream.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "3608f575-00cf-42a8-acd8-44771e584288",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1020,
        -300
      ],
      "parameters": {
        "width": 460,
        "height": 620,
        "content": "# GHL Update Contact Workflow\n\n## 1. Get Custom Fields\n  * Makes a **GET** request to the GoHighLevel API to retrieve all custom fields in the sub-account.\n  * Finds the **IA_answer** field ID to be used in the update request.\n---\n## 2. Update Contact\n  * Sends a **PUT** request to the GoHighLevel API to update the contact\u2019s **IA_answer** custom field with the sanitized AI response.\n  * In GHL, create an **Automation** that triggers when **IA_answer** is updated and sends the value by SMS to the contact.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "996bfe66-4b59-4702-aa59-55da2c5282e3",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2600,
        -300
      ],
      "parameters": {
        "color": 3,
        "width": 1120,
        "height": 1040,
        "content": "# Automating WhatsApp replies in Go High Level with Redis and Anthropic\n## Description\n* Integrates GHL + Wazzap with Redis and an AI Agent using ClientInfo to process messages, generate accurate replies, and send them via a custom field trigger.\n---\n## Who\u2019s it for\n* This workflow is for businesses using **GoHighLevel (GHL)**, including the **Wazzap** plugin for WhatsApp, who want to automate inbound SMS/WhatsApp replies with AI. It\u2019s ideal for teams that need accurate, data-driven responses from a predefined **ClientInfo** source and want to send them back to customers without paying for extra inbound automations.\n---\n## How it works / What it does\n1. **Receive message** in n8n via Webhook from GHL (**Customer Replied (SMS)** automation). WhatsApp messages arrive the same way using the **Wazzap** plugin.\n2. **Filter message type**:\n   * If audio \u2192 skip processing and send fallback asking for text.\n   * If text \u2192 sanitize by fixing escaped quotes, escaping line breaks/carriage returns/tabs, and removing invalid fields.\n3. **Buffer messages** in Redis to group multiple messages sent in a short window.\n4. **Run AI Agent** using the **ClientInfo** tool to answer only with accurate service/branch data.\n5. **Sanitize AI output** before sending back.\n6. **Update GHL contact** custom field (**IA_answer**) with the AI\u2019s response.\n7. **Send SMS reply** automatically via GHL\u2019s outbound automation triggered by the updated custom field.\n---\n## How to set up\n1. In **GHL**, create:\n   * **Inbound automation**: Trigger on *Customer Replied (SMS)* \u2192 Send to your n8n Webhook.\n   * **Outbound automation**: Trigger when **IA_answer** is updated \u2192 Send SMS to the contact.\n   * Create a custom field named **IA_answer**.\n2. Connect **Wazzap** in GHL to handle WhatsApp messages.\n3. Configure **Redis** in n8n (host, port, DB index, password).\n4. Add your **AI model** credentials (Anthropic, OpenAI, etc.) in n8n.\n5. (Optional) Set up the **Google Drive Excel Merge** sub-workflow to enrich ClientInfo with external data.\n---\n## Requirements\n* **GoHighLevel sub-account API key**.\n* **Anthropic (Claude)** API key or another supported LLM provider.\n* **Redis database** for temporary message storage.\n* **GHL automations**: one for inbound messages to n8n, one for outbound replies when **IA\\_answer** is updated.\n* **GHL custom field**: **IA\\_answer** to store and trigger replies.\n* **Wazzap plugin** in GHL for WhatsApp message handling.\n---\n## How to customize the workflow\n* Add more context or business-specific data to the **AI Agent prompt** so replies match your brand tone and policies.\n* Expand the **ClientInfo** dataset with additional services, branches, or product details.\n* Adjust the **Redis wait time** to control how long the workflow buffers messages before replying."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7ff7549a-738b-4be0-8c59-bdd9f605edfa",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "messages",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Get messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch1": {
      "main": [
        [
          {
            "node": "Sanitize and Format Message Body",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get GHL Custom fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Switch1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Sanitize and Format Message Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "messages": {
      "main": [
        [
          {
            "node": "Delete messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get messages": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save message": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download file": {
      "main": [
        [
          {
            "node": "Extract Tests",
            "type": "main",
            "index": 0
          },
          {
            "node": "Extract Sites",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Sites": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Extract Tests": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Delete messages": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GHL Custom fields": {
      "main": [
        [
          {
            "node": "Update Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Get GHL Custom fields": {
      "main": [
        [
          {
            "node": "Update Contact No audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call n8n Workflow Tool": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Sanitize and Format Message Body": {
      "main": [
        [
          {
            "node": "Save message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Download file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sanitize and Format Message Output": {
      "main": [
        [
          {
            "node": "GHL Custom fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}