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 →
{
"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.
googlePalmApihttpBearerAuthopenRouterApipineconeApiwhatsAppApiwhatsAppTriggerApi
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 →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
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
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
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
WhatsApp Agent. Uses whatsAppTrigger, agent, memoryBufferWindow, whatsApp. Event-driven trigger; 27 nodes.
Whatsapp. Uses whatsAppTrigger, agent, memoryBufferWindow, whatsApp. Event-driven trigger; 27 nodes.