AutomationFlowsAI & RAG › Handle Whatsapp Support Chats with Openrouter, Pinecone, and Gemini

Handle Whatsapp Support Chats with Openrouter, Pinecone, and Gemini

BySalman Mehboob @salmanmehboob on n8n.io

This template implements a WhatsApp support suite that logs inbound events to a dashboard API, routes conversations through an OpenRouter-powered AI agent with Pinecone RAG and memory, exposes a webhook for human outbound replies, and provides a webhook to summarize recent chats…

Event trigger★★★★★ complexityAI-powered61 nodesWhatsApp TriggerHTTP RequestWhatsAppOpenRouter ChatAgentMemory Buffer WindowHTTP Request ToolPinecone Vector Store
AI & RAG Trigger: Event Nodes: 61 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #17046 — we link there as the canonical source.

This workflow follows the Agent → Chainllm recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "aUafqkSlH9nzcQuM",
  "name": "All in One Chat Flow",
  "tags": [],
  "nodes": [
    {
      "id": "5e1a4126-749d-4c6d-9856-12ea3fa925cf",
      "name": "WhatsApp Trigger",
      "type": "n8n-nodes-base.whatsAppTrigger",
      "position": [
        304,
        352
      ],
      "parameters": {
        "options": {
          "messageStatusUpdates": [
            "sent",
            "delivered",
            "read"
          ]
        },
        "updates": [
          "messages"
        ]
      },
      "credentials": {
        "whatsAppTriggerApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6e910d80-c55e-4ae7-b7a3-ce2ff9b3319c",
      "name": "Route by Event",
      "type": "n8n-nodes-base.switch",
      "position": [
        528,
        320
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Read",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "c8cb4e77-5f59-488d-ac19-aefc74dd39fe",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.statuses[0].status }}",
                    "rightValue": "read"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Sent",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "6603939d-d8a5-4b08-aed5-21cd0add04c8",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.statuses[0].status }}",
                    "rightValue": "sent"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Delivered",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "7b1b0a07-76f1-4a6a-9f47-6c27a1121bf3",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.statuses[0].status }}",
                    "rightValue": "delivered"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "message Rcvd"
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0d41280e-9d87-40b7-9ca7-a20320e5cf59",
      "name": "Store Read",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        752,
        128
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/status/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "wa_message_id",
              "value": "={{ $json.statuses[0].id }}"
            },
            {
              "name": "status",
              "value": "read"
            },
            {
              "name": "timestamp",
              "value": "={{ $json.statuses[0].timestamp }}"
            },
            {
              "name": "recipient_phone",
              "value": "={{ $json.statuses[0].recipient_id }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "00f5c83f-4b26-4446-aac5-b92058d787b5",
      "name": "Store Sent",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        752,
        320
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/status/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "wa_message_id",
              "value": "={{ $json.statuses[0].id }}"
            },
            {
              "name": "status",
              "value": "sent"
            },
            {
              "name": "timestamp",
              "value": "={{ $json.statuses[0].timestamp }}"
            },
            {
              "name": "recipient_phone",
              "value": "={{ $json.statuses[0].recipient_id }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "afbf465e-a996-414f-8a40-cbf8daeb6ea5",
      "name": "Store Delivered",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        752,
        512
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/status/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "wa_message_id",
              "value": "={{ $json.statuses[0].id }}"
            },
            {
              "name": "status",
              "value": "delivered"
            },
            {
              "name": "timestamp",
              "value": "={{ $json.statuses[0].timestamp }}"
            },
            {
              "name": "recipient_phone",
              "value": "={{ $json.statuses[0].recipient_id }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "8f9a0bb9-7870-4208-abc3-26c8bf9838ce",
      "name": "Normalise Message",
      "type": "n8n-nodes-base.set",
      "position": [
        976,
        704
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "phone",
              "type": "string",
              "value": "={{ $('WhatsApp Trigger').item.json.contacts[0].wa_id }}"
            },
            {
              "id": "a2",
              "name": "name",
              "type": "string",
              "value": "={{ $('Contact Lookup').item.json.found ? $('Contact Lookup').item.json.contact.name : $('WhatsApp Trigger').item.json.contacts[0].profile.name }}"
            },
            {
              "id": "a3",
              "name": "wa_message_id",
              "type": "string",
              "value": "={{ $('WhatsApp Trigger').item.json.messages[0].id }}"
            },
            {
              "id": "a4",
              "name": "message_type",
              "type": "string",
              "value": "={{ $('WhatsApp Trigger').item.json.messages[0].type }}"
            },
            {
              "id": "a5",
              "name": "timestamp",
              "type": "string",
              "value": "={{ $('WhatsApp Trigger').item.json.messages[0].timestamp }}"
            },
            {
              "id": "a6",
              "name": "reaction_message_id",
              "type": "string",
              "value": "={{ $('WhatsApp Trigger').item.json.messages[0].reaction?.message_id ?? '' }}"
            },
            {
              "id": "a7",
              "name": "reaction_emoji",
              "type": "string",
              "value": "={{ $('WhatsApp Trigger').item.json.messages[0].reaction?.emoji ?? '' }}"
            },
            {
              "id": "a8",
              "name": "content",
              "type": "string",
              "value": "={{ $('WhatsApp Trigger').item.json.messages[0].text?.body ?? $('WhatsApp Trigger').item.json.messages[0][$('WhatsApp Trigger').item.json.messages[0].type]?.caption ?? ($('WhatsApp Trigger').item.json.messages[0].type === 'location' ? '\ud83d\udccd Location shared' : ($('WhatsApp Trigger').item.json.messages[0].type === 'reaction' ? $('WhatsApp Trigger').item.json.messages[0].reaction.emoji : '[' + $('WhatsApp Trigger').item.json.messages[0].type + ' message]')) }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3ebb25ec-7542-4451-84af-9793e3ec1826",
      "name": "Route by Message Type",
      "type": "n8n-nodes-base.switch",
      "position": [
        1184,
        336
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Reaction",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "reaction-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "reaction"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Text",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "text-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "text"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Image",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "image-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "image"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Video",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "video-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "video"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Audio",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "audio-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "audio"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Voice",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "voice-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "voice"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Document",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "document-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "document"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Sticker",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "sticker-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "sticker"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Location",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "location-route",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_type }}",
                    "rightValue": "location"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "unknown"
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f04a688d-5f9e-40bf-944d-ed4bee36e505",
      "name": "Store Reaction",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1472,
        176
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/status/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "wa_message_id",
              "value": "={{ $('Normalise Message').item.json.reaction_message_id }}"
            },
            {
              "name": "status",
              "value": "reaction"
            },
            {
              "name": "timestamp",
              "value": "={{ $('Normalise Message').item.json.timestamp }}"
            },
            {
              "name": "recipient_phone",
              "value": "={{ $('Normalise Message').item.json.phone }}"
            },
            {
              "name": "reaction_emoji",
              "value": "={{ $('Normalise Message').item.json.reaction_emoji }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "150095a7-2899-4875-a663-0836889f0b00",
      "name": "Store Inbound Msg",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2704,
        288
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/messages/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{ $('Normalise Message').item.json.phone }}"
            },
            {
              "name": "direction",
              "value": "inbound"
            },
            {
              "name": "name",
              "value": "={{ $('Normalise Message').item.json.name }}"
            },
            {
              "name": "wa_message_id",
              "value": "={{ $('Normalise Message').item.json.wa_message_id }}"
            },
            {
              "name": "message_type",
              "value": "={{ $('Normalise Message').item.json.message_type }}"
            },
            {
              "name": "content",
              "value": "={{ $('Normalise Message').item.json.content }}"
            },
            {
              "name": "media_url",
              "value": "={{\n$if(\n  $('Prepare Media Message').isExecuted,\n  $('Prepare Media Message').item.json.media_url,\n  ''\n)\n}}"
            },
            {
              "name": "mime_type",
              "value": "={{\n$if(\n  $('Prepare Media Message').isExecuted,\n  $('Prepare Media Message').item.json.mime_type,\n  ''\n)\n}}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "1017cc63-ed37-4b71-9f22-4bb222f9bd00",
      "name": "Case Open Check",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2960,
        240
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/cases/lookup",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{ $('Normalise Message').item.json.phone }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "f629575c-1064-4d85-ba5c-a3210754422a",
      "name": "Case Open?",
      "type": "n8n-nodes-base.if",
      "position": [
        3216,
        240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "case-open-check",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.case.status }}"
            },
            {
              "id": "31367b8c-218c-4807-904e-59cffd5b03df",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.case.status }}",
              "rightValue": "open"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "20c6d5b5-9d4d-4718-b40f-da4a4555782f",
      "name": "Prepare Agent Reply",
      "type": "n8n-nodes-base.set",
      "position": [
        4528,
        608
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "phone",
              "name": "phone",
              "type": "string",
              "value": "={{ $('Normalise Message').item.json.phone }}"
            },
            {
              "id": "reply",
              "name": "reply",
              "type": "string",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "153b1272-3e82-4c05-b9d1-d702bae70294",
      "name": "Send message",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        4752,
        608
      ],
      "parameters": {
        "textBody": "={{ $('Prepare Agent Reply').item.json.reply }}",
        "operation": "send",
        "phoneNumberId": "1183690101495838",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Prepare Agent Reply').item.json.phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "7f7c1fa6-9f80-498b-80c1-02b5d5e15a49",
      "name": "Store Outbound Msg",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4976,
        608
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/messages/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{ $('Prepare Agent Reply').item.json.phone }}"
            },
            {
              "name": "direction",
              "value": "outbound"
            },
            {
              "name": "wa_message_id",
              "value": "={{ $json.messages[0].id }}"
            },
            {
              "name": "message_type",
              "value": "text"
            },
            {
              "name": "content",
              "value": "={{ $('Prepare Agent Reply').item.json.reply }}"
            },
            {
              "name": "sent_by",
              "value": "ai"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "b9a415a7-da50-40d9-9703-23d0a214d883",
      "name": "OpenRouter Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        3904,
        848
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c09a53e7-a8ab-49b9-8e50-2a57e87452d4",
      "name": "AI Agent1",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        4128,
        608
      ],
      "parameters": {
        "text": "={{ $('Normalise Message').item.json.content }}",
        "options": {
          "maxIterations": 10,
          "systemMessage": "=You are a friendly, professional WhatsApp customer support assistant for a business.\n\nKeep your responses warm, natural, and concise, just like a real WhatsApp conversation. Avoid long explanations unless the customer specifically asks for more detail.\n\n**Customer Information**\n\n* Customer name: `{{ $('Normalise Message').first().json.name }}`\n* Customer phone: `{{ $('Normalise Message').first().json.phone }}`\n\n## Your Responsibilities\n\nYour primary goal is to resolve the customer's issue yourself whenever possible.\n\nHowever, if the issue requires human assistance, you **must** use the **Create Case** tool immediately.\n\n### Always Create a Case if:\n\n* The customer requests to speak with a human, agent, representative, manager, or support team.\n* The customer insists on talking to a person, even if you could answer the question.\n* The issue involves refunds, billing, payments, invoices, charges, or financial disputes.\n* The customer has a complaint or is dissatisfied.\n* The customer is upset, angry, or frustrated.\n* The issue requires investigation or access that you do not have.\n* The problem is complex, unclear, or cannot be fully resolved by you.\n* You are uncertain about the correct answer.\n* The customer asks you to create a support ticket or case.\n\n## Important Context\n\nYou will **only receive customer messages when there is NO open case** for that customer.\n\nIf there is already an open case, the system routes messages elsewhere and you will not receive them.\n\nTherefore:\n\n* Never assume a case already exists.\n* If the conversation requires human assistance according to the rules above, always create a new case immediately.\n* Do not hesitate or ask for permission first if the situation clearly requires escalation.\n\n## When Creating a Case\n\nUse the **Create Case** tool.\n\nWrite the case so that a human support agent who has **never seen this conversation** can immediately understand the situation.\n\nInclude:\n\n**Title**\n\n* A short, specific summary of the issue.\n\n**Briefing**\n\n* What the customer wants.\n* Relevant background and important details.\n* Any troubleshooting already attempted (if applicable).\n* What action the customer is expecting.\n\n**Suggested Replies**\nProvide **1\u20133 short, ready-to-send WhatsApp replies** that the human agent can send directly to continue the conversation.\n\n## After Creating a Case\n\nDo **not** continue troubleshooting.\n\nSimply reassure the customer with a short message such as:\n\n\"Thanks! I've forwarded your request to our support team. A human agent will get back to you as soon as possible.\"\n\n## If No Case Is Needed\n\nAnswer the customer's question directly.\n\nKeep responses:\n\n* Friendly\n* Professional\n* Accurate\n* Short and conversational\n* Appropriate for WhatsApp\n\nOnly ask follow-up questions when they are genuinely needed to resolve the customer's request."
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "6350af28-05b5-4f85-b467-b152e4b608a7",
      "name": "Contact Lookup",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        752,
        704
      ],
      "parameters": {
        "url": "=http://host.docker.internal:3001/api/contacts/lookup?phone={{ $json.contacts[0].wa_id }}",
        "options": {
          "response": {}
        },
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "405b56d0-ca37-460b-8c2a-c5df6618a2a6",
      "name": "Get Media URL",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        1856,
        592
      ],
      "parameters": {
        "resource": "media",
        "operation": "mediaUrlGet",
        "mediaGetId": "={{ $('WhatsApp Trigger').item.json.messages[0][$('WhatsApp Trigger').item.json.messages[0].type].id }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "e5d860f8-dcc1-4634-b7cf-ce5fee5ebcec",
      "name": "Download Media",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2048,
        592
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "whatsAppApi"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "a0546bff-8584-4daf-9157-914523f2a0cb",
      "name": "Upload Media",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2240,
        592
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/media/upload",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            },
            {
              "name": "message_type",
              "value": "={{ $('Normalise Message').item.json.message_type }}"
            },
            {
              "name": "wa_message_id",
              "value": "={{ $('Normalise Message').item.json.wa_message_id }}"
            },
            {
              "name": "mime_type",
              "value": "={{ $('Get Media URL').item.json.mime_type }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "3c1fa383-ddbb-486a-aa47-83d8e82c1f0d",
      "name": "Prepare Media Message",
      "type": "n8n-nodes-base.set",
      "position": [
        2432,
        592
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "m1",
              "name": "media_url",
              "type": "string",
              "value": "={{ $('Upload Media').item.json.media_url }}"
            },
            {
              "id": "m2",
              "name": "mime_type",
              "type": "string",
              "value": "={{ $('Upload Media').item.json.mime_type }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "46f1e8c0-eed9-4f60-8871-6682e9f6eb72",
      "name": "Prepare Static Reply",
      "type": "n8n-nodes-base.set",
      "position": [
        3872,
        256
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "sr1",
              "name": "phone",
              "type": "string",
              "value": "={{ $('Normalise Message').item.json.phone }}"
            },
            {
              "id": "sr2",
              "name": "reply",
              "type": "string",
              "value": "Thanks for your message! I can only read text messages right now. Please type your question and I'll help you right away."
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "01c40997-efbd-4164-b7a7-c234edfebb63",
      "name": "Send Static Reply",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        4112,
        256
      ],
      "parameters": {
        "textBody": "={{ $('Prepare Static Reply').item.json.reply }}",
        "operation": "send",
        "phoneNumberId": "1183690101495838",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Prepare Static Reply').item.json.phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "8df856ad-a7dd-4a9e-9220-7fe355b0aa22",
      "name": "Store Static Outbound",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4336,
        256
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/messages/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{ $('Prepare Static Reply').item.json.phone }}"
            },
            {
              "name": "direction",
              "value": "outbound"
            },
            {
              "name": "wa_message_id",
              "value": "={{ $json.messages[0].id }}"
            },
            {
              "name": "message_type",
              "value": "text"
            },
            {
              "name": "content",
              "value": "={{ $('Prepare Static Reply').item.json.reply }}"
            },
            {
              "name": "sent_by",
              "value": "ai"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "c1652241-b9ed-45f2-9d73-e907377c6588",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        4192,
        832
      ],
      "parameters": {
        "sessionKey": "={{ $('Normalise Message').first().json.phone }}",
        "sessionIdType": "customKey"
      },
      "typeVersion": 1.4
    },
    {
      "id": "69249c00-0195-42b5-abf1-d445c3e74e65",
      "name": "Create Case",
      "type": "n8n-nodes-base.httpRequestTool",
      "position": [
        4416,
        992
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/cases/create",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{ $('Normalise Message').first().json.phone }}"
            },
            {
              "name": "title",
              "value": "={{ $fromAI('title', 'A short specific case title naming the customer actual problem (for example: Refund request for damaged order, or Cannot log into account). Never generic like Customer inquiry.', 'string') }}"
            },
            {
              "name": "summary",
              "value": "={{ $fromAI('summary', 'A briefing for the human agent who will take over: what the customer wants, the key details and context they gave, and anything already told to them. Written so the agent understands the problem without reading the whole conversation.', 'string') }}"
            },
            {
              "name": "urgency",
              "value": "={{ $fromAI('urgency', 'Urgency: low for a general question, medium for an issue needing attention, high for an upset customer or a refund/billing/payment or a time-sensitive matter or an explicit request for a human.', 'string') }}"
            },
            {
              "name": "ai_suggestion_1",
              "value": "={{ $fromAI('suggestion1', 'A complete ready-to-send reply the human agent can send to the customer to address their problem. An actual professional message, not a description of what to say.', 'string') }}"
            },
            {
              "name": "ai_suggestion_2",
              "value": "={{ $fromAI('suggestion2', 'A second complete ready-to-send reply option for the human agent, taking a slightly different angle from the first.', 'string') }}"
            },
            {
              "name": "ai_suggestion_3",
              "value": "={{ $fromAI('suggestion3', 'A third complete ready-to-send reply option for the human agent.', 'string') }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "toolDescription": "Create a support case when the customer has an issue that needs human agent attention or escalation (a complaint, a complex issue AI cannot resolve, an explicit request for a human, or refund/billing/urgent matters). Provide a clear title, a detailed summary, an urgency level (low/medium/high), and three suggested replies for the human agent."
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "60a58c2b-50c8-4490-89e4-90340e87f864",
      "name": "Reply Router",
      "type": "n8n-nodes-base.if",
      "position": [
        3568,
        288
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "reply-text-check",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $('Normalise Message').item.json.message_type }}",
              "rightValue": "text"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "73919237-9fa2-4054-b870-a368f3813818",
      "name": "Knowledge Base",
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "position": [
        4544,
        976
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "options": {
          "pineconeNamespace": "company-kb"
        },
        "pineconeIndex": {
          "__rl": true,
          "mode": "list",
          "value": "company-knowledge-base",
          "cachedResultName": "company-knowledge-base"
        },
        "toolDescription": "Search the company knowledge base for facts about products, pricing, features, and policies before answering a customer question.",
        "includeDocumentMetadata": false
      },
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "55617bc9-c55e-4433-8965-72881bee6c7d",
      "name": "Gemini",
      "type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
      "position": [
        4576,
        1232
      ],
      "parameters": {
        "modelName": "models/gemini-embedding-2"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0ee62081-9f35-4b31-b76b-6c42c88a7bb1",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        224,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 1500,
        "height": 1020,
        "content": "## Inbound webhook, status events & message routing\n\nWhatsApp trigger. Routes status events (read / sent / delivered) to the API, and messages through contact lookup, normalise, message-type switch and reaction logging."
      },
      "typeVersion": 1
    },
    {
      "id": "16796773-40ca-487a-a39b-3998d8ea90eb",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1744,
        432
      ],
      "parameters": {
        "color": 7,
        "width": 960,
        "height": 330,
        "content": "## Media: fetch, download & upload\n\nFor image / audio / video / document messages: resolve the WhatsApp media URL, download it, upload to storage, and build the media message."
      },
      "typeVersion": 1
    },
    {
      "id": "6511fd25-de66-476c-be06-d9332f911ee9",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2624,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 824,
        "height": 320,
        "content": "## Persist message & open-case check\n\nStore the inbound message, then check the dashboard API for an already-open case on this conversation."
      },
      "typeVersion": 1
    },
    {
      "id": "a76e9c01-0e53-47ce-bb46-881e89db0199",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3456,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 360,
        "height": 340,
        "content": "## Reply routing\n\nOpen case \u2192 hand to the AI agent. No open case \u2192 send the static auto-reply."
      },
      "typeVersion": 1
    },
    {
      "id": "09ba3fb6-6fa7-4d02-9251-e9760cc2f4fb",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3824,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 708,
        "height": 336,
        "content": "## Auto-reply branch (no open case)\n\nPrepare and send a static WhatsApp reply, then log it to the dashboard."
      },
      "typeVersion": 1
    },
    {
      "id": "48e0504b-f669-4a10-a7cc-a243924d54bc",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3824,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 1440,
        "height": 940,
        "content": "## AI agent \u2014 RAG, memory & reply send\n\nAI Agent (OpenRouter model, buffer memory, Pinecone Knowledge Base with Gemini embeddings, Create-Case tool) drafts a reply, which is sent on WhatsApp and stored."
      },
      "typeVersion": 1
    },
    {
      "id": "b0a18294-79ba-4864-9f54-5ee651ed17da",
      "name": "Outbound Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        928,
        2304
      ],
      "parameters": {
        "path": "ps-outbound-send",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "586a0b44-e4a6-4323-a2da-b6ebbec61f88",
      "name": "Has Media?",
      "type": "n8n-nodes-base.if",
      "position": [
        1152,
        2304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "media-check",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.body.media_url }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "5a615f98-0554-4372-a060-0373c11a428e",
      "name": "Log Outbound",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2272,
        2256
      ],
      "parameters": {
        "url": "http://host.docker.internal:3001/api/messages/store",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{ $(\"Outbound Webhook\").item.json.body.phone }}"
            },
            {
              "name": "direction",
              "value": "outbound"
            },
            {
              "name": "wa_message_id",
              "value": "={{ $json.messages[0].id }}"
            },
            {
              "name": "message_type",
              "value": "={{ $(\"Outbound Webhook\").item.json.body.message_type }}"
            },
            {
              "name": "content",
              "value": "={{ $(\"Outbound Webhook\").item.json.body.content }}"
            },
            {
              "name": "media_url",
              "value": "={{ $(\"Outbound Webhook\").item.json.body.media_url }}"
            },
            {
              "name": "mime_type",
              "value": "={{ $(\"Outbound Webhook\").item.json.body.mime_type }}"
            },
            {
              "name": "sent_by",
              "value": "human"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "fe41c657-bc2b-4caa-a115-174ecacf6ab7",
      "name": "Send Text",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        1760,
        2784
      ],
      "parameters": {
        "textBody": "={{ $json.body.content }}",
        "operation": "send",
        "phoneNumberId": "1183690101495838",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $json.body.phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "c11ea501-b7d3-4890-86c8-adf232402652",
      "name": "Respond OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2464,
        2256
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"ok\": true, \"message_id\": $json.message_id } }}"
      },
      "typeVersion": 1.5
    },
    {
      "id": "55e71f56-ea71-4e5d-aa83-10c8eb41cc15",
      "name": "Route By Media Type",
      "type": "n8n-nodes-base.switch",
      "position": [
        1520,
        2096
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Image",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "5ceb26f5-b6b3-4704-bb86-65db6d58aae3",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.body.message_type }}",
                    "rightValue": "image"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "video",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "9959ff8b-513b-4ceb-b090-1f6dd9873f96",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.body.message_type }}",
                    "rightValue": "video"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Document",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "1e33bfe7-ff4d-40a1-9403-189c4d20c05e",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.body.message_type }}",
                    "rightValue": "document"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Audio",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e897d5ae-636c-42a1-b8cd-57ccea72b107",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.body.message_type }}",
                    "rightValue": "audio"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "3bfc155c-64c1-410a-804c-d36bc684c426",
      "name": "Send Media - Image",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        1744,
        1840
      ],
      "parameters": {
        "mediaLink": "={{ $json.body.media_url }}",
        "operation": "send",
        "messageType": "image",
        "phoneNumberId": "1183690101495838",
        "additionalFields": {
          "mediaCaption": "={{ $json.body.content ?? '' }}"
        },
        "recipientPhoneNumber": "={{ $json.body.phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "afcfa9f9-50dd-4fd5-8e79-87b16f3d8a6f",
      "name": "Send Media - Video",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        1744,
        2032
      ],
      "parameters": {
        "mediaLink": "={{ $json.body.media_url }}",
        "operation": "send",
        "messageType": "video",
        "phoneNumberId": "1183690101495838",
        "additionalFields": {
          "mediaCaption": "={{ $json.body.content ?? '' }}"
        },
        "recipientPhoneNumber": "={{ $json.body.phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "251636c8-5d03-4e58-a67f-5f5450214d8a",
      "name": "Send Media - Document",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        1744,
        2224
      ],
      "parameters": {
        "mediaLink": "={{ $json.body.media_url }}",
        "operation": "send",
        "messageType": "document",
        "phoneNumberId": "1183690101495838",
        "additionalFields": {
          "mediaCaption": "={{ $json.body.content ?? '' }}"
        },
        "recipientPhoneNumber": "={{ $json.body.phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "ad689e34-09dd-4477-a874-a834b3560282",
      "name": "Send Media - Audio",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        1744,
        2416
      ],
      "parameters": {
        "mediaLink": "={{ $json.body.media_url }}",
        "operation": "send",
        "messageType": "audio",
        "phoneNumberId": "1183690101495838",
        "additionalFields": {
          "mediaCaption": "={{ $json.body.content ?? '' }}"
        },
        "recipientPhoneNumber": "={{ $json.body.phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "87b548c6-57da-47d2-a77e-386a9f25d018",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        2176
      ],
      "parameters": {
        "color": 7,
        "width": 600,
        "height": 340,
        "content": "## Outbound webhook & media check\n\nDashboard POSTs here to send a message. Branch on whether a media URL is present."
      },
      "typeVersion": 1
    },
    {
      "id": "9316e355-7e20-430f-b75c-291690427732",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1456,
        1680
      ],
      "parameters": {
        "color": 7,
        "width": 620,
        "height": 880,
        "content": "## Route & send media\n\nSwitch on message type and send the image / video / document / audio via WhatsApp."
      },
      "typeVersion": 1
    },
    {
      "id": "1fc937c8-68da-40c1-9558-b0fce61d0533",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1616,
        2608
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 332,
        "content": "## Send text\n\nNo media \u2192 send a plain WhatsApp text message."
      },
      "typeVersion": 1
    },
    {
      "id": "c26ffea9-61d8-4d44-80eb-ee30fd7f16ec",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2208,
        2128
      ],
      "parameters": {
        "color": 7,
        "width": 620,
        "height": 300,
        "content": "## Log outbound & respond\n\nLog the sent message to the dashboard API and return OK to the caller."
      },
      "typeVersion": 1
    },
    {
      "id": "082f6db1-d3f1-469e-b788-7ff1a7742d93",
      "name": "Summarize Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        3216,
        2160
      ],
      "parameters": {
        "path": "ps-summarize",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "d6e0d7f0-4f99-4b5b-84db-fe9abff4d165",
      "name": "Fetch Messages",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3440,
        2160
      ],
      "parameters": {
        "url": "=http://host.docker.internal:3001/api/messages/recent?phone={{ $json.body.phone }}&limit={{ $json.body.limit }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "af50c825-f5c0-43f5-bb11-504a8d46b47c",
      "name": "Summarize",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        3728,
        2160
      ],
      "parameters": {
        "text": "=Summarize this WhatsApp customer-support conversation for a human agent who is about to take over. Be concise: cover the customer's main issue, the key details, what has already been done or said, and what still needs action.\n\nConversation ({{ $json.count }} messages):\n{{ $json.messages.map(m => m.from.toUpperCase() + ': ' + m.text).join('\\n') }}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "You write short, clear handoff summaries of customer-support chats for human agents. Plain language, brief, no preamble."
            }
          ]
        },
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "adff1895-a3c2-4cff-a989-c2efe5938372",
      "name": "OpenRouter Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        3808,
        2384
      ],
      "parameters": {
        "model": "openrouter/free",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "eb52a5d2-4862-4ac1-ba8f-2d57f117e6e8",
      "name": "Respond Summary",
      "type": "n8n-nodes-base.respondToWebhook",
      "po

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This template implements a WhatsApp support suite that logs inbound events to a dashboard API, routes conversations through an OpenRouter-powered AI agent with Pinecone RAG and memory, exposes a webhook for human outbound replies, and provides a webhook to summarize recent chats…

Source: https://n8n.io/workflows/17046/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

The "WhatsApp Productivity Assistant with Memory and AI Imaging" is a comprehensive n8n workflow that transforms your WhatsApp into a powerful, multi-talented AI assistant. It's designed to handle a w

WhatsApp Trigger, Agent, HTTP Request +20
AI & RAG

A production-ready 3-workflow system that handles customer support across WhatsApp and Email using RAG-powered AI. Automatically routes queries, detects escalation intent, logs handoffs to Google Shee

Form Trigger, Pinecone Vector Store, Document Default Data Loader +12
AI & RAG

Automatically ingest your knowledge base, monitor your LinkedIn company page inbox, and reply to leads and customers with AI-drafted, source-grounded answers. Classifies every message, checks for spam

Google Drive Trigger, Google Drive, Pinecone Vector Store +9
AI & RAG

WhatsApp Agent. Uses whatsAppTrigger, agent, memoryBufferWindow, whatsApp. Event-driven trigger; 27 nodes.

WhatsApp Trigger, Agent, Memory Buffer Window +9
AI & RAG

Whatsapp. Uses whatsAppTrigger, agent, memoryBufferWindow, whatsApp. Event-driven trigger; 27 nodes.

WhatsApp Trigger, Agent, Memory Buffer Window +9