{
  "id": "BjtkwzFW1RrYmDXS",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "WA CS 3Our",
  "tags": [],
  "nodes": [
    {
      "id": "49348b5f-2375-44e0-bf6b-0d471d6db385",
      "name": "\ud83e\udd16 WhatsApp AI Customer Service Agent",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1136,
        80
      ],
      "parameters": {
        "width": 608,
        "height": 704,
        "content": "## \ud83e\udd16 WhatsApp AI Customer Service Agent\n\nTurn WhatsApp into a 24/7 AI customer service channel. An AI agent (Google Gemini) answers using your knowledge base in Google Sheets, replies with a natural typing effect, and hands off to a human when needed.\n\n### \u2699\ufe0f How it works\n1. OpenWA Trigger listens for incoming messages and reactions.\n2. If no human handover is active, the AI Agent answers from the knowledge base.\n3. Admin keywords pause the AI and route the chat to a human.\n4. React with \u2705 to hand the chat back to the AI.\n\n### \ud83d\udee0\ufe0f Setup\n1. Connect WhatsApp via the OpenWA node.\n2. Add your Google Gemini API key to the Chat Model node.\n3. Connect Google Sheets and point the sheet nodes to your own Sheet.\n4. Fill the knowledge base sheet with your FAQ / product info.\n\n**Requirements:** WhatsApp + OpenWA, Google Gemini API key, Google Sheets account.\n\n\u26a0\ufe0f Replace all sample Google Sheet IDs and credentials with your own before publishing."
      },
      "typeVersion": 1
    },
    {
      "id": "caa66d1f-0f0f-4d5f-891c-98cdf79befd5",
      "name": "Row Human Handle",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        496,
        928
      ],
      "parameters": {
        "columns": {
          "value": {
            "nama": "={{  $('OpenWA Trigger').item.json.data.contact?.pushName || ''  }}",
            "chatId": "={{  $('OpenWA Trigger').item.json.data.chatId || $('OpenWA Trigger').item.json.data.from  }}",
            "timestamp": "={{  $now.toISO()  }}"
          },
          "schema": [
            {
              "id": "chatId",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "chatId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "nama",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "nama",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "chatId\ttimestamp\tnama"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 849475902,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit#gid=849475902",
          "cachedResultName": "Session Chat"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit?usp=drivesdk",
          "cachedResultName": "S&K database 3our"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "99007c0d-62b7-40bc-a040-1befa1489d84",
      "name": "Set AI Handle",
      "type": "n8n-nodes-base.code",
      "position": [
        -48,
        80
      ],
      "parameters": {
        "jsCode": "const d = $json.data || {};\nconst chatId = d.chatId || d.senderId || '';\nconst r = d.reaction;\nconst emoji = typeof r === 'string' ? r : (r && r.text) || '';\nconst ok = chatId && (emoji.includes('\u2705') || emoji.includes('\u2611'));\nreturn ok ? [{ json: { chatId } }] : [];"
      },
      "retryOnFail": true,
      "typeVersion": 2
    },
    {
      "id": "206a3b11-ce4b-4047-9725-0dda3cf70fba",
      "name": "Delete Session Row",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        368,
        80
      ],
      "parameters": {
        "operation": "delete",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 849475902,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit#gid=849475902",
          "cachedResultName": "Session Chat"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit?usp=drivesdk",
          "cachedResultName": "S&K database 3our"
        },
        "startIndex": "={{  $json.row_number  }}",
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c28b78fa-049d-4374-8ab7-4471102033c5",
      "name": "Find Session Row",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        160,
        80
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{  $json.chatId  }}",
              "lookupColumn": "chatId"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 849475902,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit#gid=849475902",
          "cachedResultName": "Session Chat"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit?usp=drivesdk",
          "cachedResultName": "S&K database 3our"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "196d99be-a547-44a3-964e-6ceb3fd80f0c",
      "name": "Session Lookup",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        624,
        448
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{  $('OpenWA Trigger').item.json.data.chatId || $('OpenWA Trigger').item.json.data.from  }}",
              "lookupColumn": "chatId"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 849475902,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit#gid=849475902",
          "cachedResultName": "Session Chat"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit?usp=drivesdk",
          "cachedResultName": "S&K database 3our"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "4579618f-4cc8-453d-99ab-9e5f29cc0bfa",
      "name": "Check Mode",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        448
      ],
      "parameters": {
        "jsCode": "const rows = $input.all();\nconst matched = rows.some(r => r.json && r.json.chatId !== undefined && r.json.chatId !== null && String(r.json.chatId).trim() !== '');\nif (matched) return [];\nreturn $('If Personal Chat (c.us)').all();"
      },
      "retryOnFail": true,
      "typeVersion": 2
    },
    {
      "id": "88c62cc5-5f2f-4ad0-9e2e-305996af4e70",
      "name": "Send a text message",
      "type": "@rmyndharis/n8n-nodes-openwa.openWa",
      "position": [
        496,
        784
      ],
      "parameters": {
        "chatId": "={{  $('OpenWA Trigger').item.json.data.chatId || $('OpenWA Trigger').item.json.data.from  }}",
        "message": "={{  $('AI Agent').item.json.output  }}",
        "sessionId": "eac40d14-9906-4d66-84b0-209155394e58"
      },
      "credentials": {
        "openWaApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "483aca5f-99e3-493d-8f2e-a60e1f5ce236",
      "name": "OpenWA Trigger",
      "type": "@rmyndharis/n8n-nodes-openwa.openWaTrigger",
      "position": [
        -496,
        288
      ],
      "parameters": {
        "events": [
          "message.received",
          "message.reaction"
        ],
        "sessionId": "eac40d14-9906-4d66-84b0-209155394e58"
      },
      "credentials": {
        "openWaApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bb56a340-e906-427d-8e00-ba830528faa7",
      "name": "If Admin Words",
      "type": "n8n-nodes-base.if",
      "position": [
        288,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "9d7f7782-c624-40dc-a6b4-d48533f54bbc",
              "operator": {
                "type": "string",
                "operation": "notContains"
              },
              "leftValue": "={{ $json.output }}",
              "rightValue": "#admin"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8eefcd4c-9d74-4b30-921f-6ce37f8a43bf",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        656
      ],
      "parameters": {
        "color": 3,
        "width": 1104,
        "height": 528,
        "content": "## AI handle / Human Loop\nThe AI Agent answers the customer using the knowledge base. If an admin keyword is detected, the chat is handed to a human (Row Human Handle) and the AI is paused."
      },
      "typeVersion": 1
    },
    {
      "id": "e860ba88-c98f-48ee-9851-4da2c1ad3fd8",
      "name": "Database Company",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        144,
        1024
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 41195735,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit#gid=41195735",
          "cachedResultName": "EKB - CS"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1AcYRkZmiT44-flXBwIid1zejIkYDe8-l-5pgULIClVE/edit?usp=drivesdk",
          "cachedResultName": "S&K 3our"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "03098eb9-3a52-449d-ac41-4eadebe0ed42",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        336
      ],
      "parameters": {
        "color": 4,
        "width": 1104,
        "height": 272,
        "content": "## Check If Reaction False\nif not detect reaction or not detect session chat on sheets, AI will handle the chat"
      },
      "typeVersion": 1
    },
    {
      "id": "7398a0b2-f971-4116-ac5c-eb8e59179135",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        32,
        1024
      ],
      "parameters": {
        "sessionKey": "={{  $('OpenWA Trigger').item.json.data.chatId }}",
        "sessionIdType": "customKey",
        "contextWindowLength": 3
      },
      "typeVersion": 1.3
    },
    {
      "id": "aacd5d3f-43fa-4277-8655-4a532f731d1f",
      "name": "Think",
      "type": "@n8n/n8n-nodes-langchain.toolThink",
      "position": [
        256,
        1024
      ],
      "parameters": {
        "description": "pastikan semua data yang ditanyakan customer sesuai. cek penulisan jika kemungkinan besar kecinya berbeda. Jika tidak ada jawaban, beri tahu customer kalau kamu tidak tahu. Pastikan jangan tawarkan dilanjutkan ke admin/CS jika customer tidak meminta diteruskan ke admin/CS."
      },
      "typeVersion": 1
    },
    {
      "id": "fd79d339-48e6-4cee-99bf-f483ff9b2e59",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        -64,
        1024
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3cd7452c-832d-421e-b785-abd19692dc03",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -64,
        800
      ],
      "parameters": {
        "text": "={{  $('OpenWA Trigger').item.json.data.body  }}",
        "options": {
          "systemMessage": "=Kamu adalah AI Agent Customer Service untuk 3Our Agency.\n\nSapa customer dengan ramah (panggil \"kak\"). Jawab pertanyaan customer dengan bahasa Indonesia yang santai & friendly, HANYA berdasarkan data referensi yang ada di Tool Google Sheets (Database Company).\n\nPesan dari customer: {{  $('OpenWA Trigger').item.json.data.body  }}\n\nTawarkan bantuan lain di akhir percakapan secara variatif agar percakapan tidak terputus.\n\nATURAN PENTING soal eskalasi ke admin/CS manusia:\n- Jika jawaban TIDAK ditemukan / tidak relevan di data Google Sheets, ATAU customer secara eksplisit minta dihubungkan ke admin/CS manusia, maka JANGAN mengarang jawaban. Balas dengan sopan bahwa kamu akan menghubungkan ke tim CS, lalu di BARIS TERAKHIR tulis token persis: #admin\n- Token #admin WAJIB ditulis huruf kecil, diawali tanda pagar, dan hanya muncul ketika kamu memang perlu mengeskalasi. Jangan pernah menuliskan #admin jika kamu bisa menjawab dari data Sheets.\n- Selama kamu bisa menjawab dari data Sheets, JANGAN tulis #admin sama sekali."
        },
        "promptType": "define"
      },
      "typeVersion": 2.1
    },
    {
      "id": "3290828f-354b-4e14-a177-20955bbe3e38",
      "name": "If reaction",
      "type": "n8n-nodes-base.if",
      "position": [
        -256,
        288
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "9392ee72-ff42-40fc-b612-ca51ec0df93b",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{  $json.event  }}",
              "rightValue": "message.reaction"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "73d5de86-97ec-4ddd-8c14-6d43d2083313",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 1104,
        "height": 272,
        "content": "## Check If Reaction True\nif detect reaction, this node will delete chat session ID from sheets"
      },
      "typeVersion": 1
    },
    {
      "id": "bbe67337-ccf1-4490-b9fc-8310c6f9f7da",
      "name": "If FromMe",
      "type": "n8n-nodes-base.if",
      "position": [
        144,
        448
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "bb227c07-cc0a-42f9-be24-b2d0eba39457",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.payload._data.key.fromMe }}",
              "rightValue": "true"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "98b32940-87a4-4686-8b27-271062bffce4",
      "name": "If Personal Chat (c.us)",
      "type": "n8n-nodes-base.if",
      "position": [
        416,
        464
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "49985d46-d7d3-4503-aa9a-5cac9334a05d",
              "operator": {
                "type": "string",
                "operation": "endsWith"
              },
              "leftValue": "={{ $json.payload.from }}",
              "rightValue": "@c.us"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3e2023d4-2500-4bed-864e-6e353f4aa9a6",
      "name": "Payload Check",
      "type": "n8n-nodes-base.set",
      "position": [
        -48,
        448
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1ece9695-a75a-4ff5-858d-f0a9713c022f",
              "name": "payload.from",
              "type": "string",
              "value": "={{  $json.data.chatId || $json.data.from  }}"
            },
            {
              "id": "24e11376-11e0-4042-8390-5b4a5d4f2225",
              "name": "payload.source",
              "type": "string",
              "value": "={{  $json.data.source || ($json.data.fromMe ? 'app' : 'unknown')  }}"
            },
            {
              "id": "994609df-9f3b-4ad6-9a5f-af9d1f8d67f2",
              "name": "payload._data.key.fromMe",
              "type": "boolean",
              "value": "={{  $json.data.fromMe || false  }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "ae5277ed-9bd3-4c2e-a31e-ab50d65d92f9",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        128
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 336,
        "content": "## Trigger & Routing\nReceives incoming WhatsApp messages and reactions, then routes each event to the right path."
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "ac93289a-d856-4199-a8cd-642c6e42ea10",
  "nodeGroups": [],
  "connections": {
    "Think": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "If Admin Words",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If FromMe": {
      "main": [
        [],
        [
          {
            "node": "If Personal Chat (c.us)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Mode": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If reaction": {
      "main": [
        [
          {
            "node": "Set AI Handle",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Payload Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Payload Check": {
      "main": [
        [
          {
            "node": "If FromMe",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set AI Handle": {
      "main": [
        [
          {
            "node": "Find Session Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "If Admin Words": {
      "main": [
        [
          {
            "node": "Send a text message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Row Human Handle",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenWA Trigger": {
      "main": [
        [
          {
            "node": "If reaction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Session Lookup": {
      "main": [
        [
          {
            "node": "Check Mode",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Database Company": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Find Session Row": {
      "main": [
        [
          {
            "node": "Delete Session Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Personal Chat (c.us)": {
      "main": [
        [
          {
            "node": "Session Lookup",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}