This workflow follows the HTTP Request → Slack 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 →
{
"nodes": [
{
"parameters": {
"content": "## AI front desk for texts and webchat\n- A customer texts or chats in, the AI answers like the office and remembers each customer's thread\n- Hot leads get tagged and sales gets pinged, hard ones go straight to a person",
"height": 180,
"width": 440
},
"id": "sticky-title",
"name": "What This Flow Does",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-420,
-260
]
},
{
"parameters": {
"content": "## The AI front desk\n- Answers like someone at the office, using the customer's full thread so it never loses the plot\n- Flags the ones ready to buy and steps aside for a person when the message is a complaint, an emergency, or anything it is not sure about",
"height": 180,
"width": 440
},
"id": "sticky-agent",
"name": "How The AI Behaves",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
820,
-300
]
},
{
"parameters": {
"httpMethod": "POST",
"path": "demo/agent-message",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-agent-message",
"name": "Customer Sent A Message",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
0,
0
]
},
{
"parameters": {
"jsCode": "// GoHighLevel sends a few different shapes depending on how the webhook action is set up.\nconst body = $json.body ?? $json;\nconst contact = body.contact ?? {};\nconst message = (typeof body.message === 'object' && body.message !== null) ? body.message : {};\n\nconst contactId = String(body.contact_id ?? body.contactId ?? contact.id ?? '');\nconst first = contact.firstName ?? body.first_name ?? '';\nconst last = contact.lastName ?? body.last_name ?? '';\nconst name = String(body.full_name ?? body.name ?? contact.name ?? [first, last].filter(Boolean).join(' ')).trim() || 'there';\n\nlet phone = String(body.phone ?? contact.phone ?? '').replace(/[^\\d]/g, '');\nif (phone) phone = '+' + phone;\n\nconst channelRaw = String(body.channel ?? message.type ?? body.message_type ?? 'SMS');\nconst channel = /chat|live/i.test(channelRaw) ? 'webchat' : 'SMS';\n\nconst messageText = String(message.body ?? (typeof body.message === 'string' ? body.message : undefined) ?? body.text ?? '').trim();\n\n// Only answer messages the customer sent. If GoHighLevel echoes one of our own outbound\n// texts back at this webhook, the bot stays quiet instead of talking to itself.\nconst direction = String(message.direction ?? body.direction ?? 'inbound').toLowerCase();\nconst fromCustomer = direction !== 'outbound' && messageText !== '';\n\nreturn [{ json: { contactId, name, phone, channel, messageText, fromCustomer } }];"
},
"id": "code-read-message",
"name": "Read The Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
220,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.fromCustomer }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-from-customer",
"name": "Did The Customer Send This?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
440,
0
]
},
{
"parameters": {
"jsCode": "// Each contact gets their own running thread, stored inside the workflow itself.\nconst staticData = $getWorkflowStaticData('global');\nstaticData.conversations = staticData.conversations ?? {};\nconst history = staticData.conversations[$json.contactId] ?? [];\n\n// Keep the last 10 back-and-forth turns so the AI remembers the thread without it growing forever.\nconst recent = history.slice(-20);\nconst lines = recent.map(t => (t.role === 'customer' ? 'Customer: ' : 'Front desk: ') + t.text);\nlines.push('Customer: ' + $json.messageText);\n\nreturn [{ json: { ...$json, transcript: lines.join('\\n') } }];"
},
"id": "code-pull-history",
"name": "Pull Up This Conversation",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
660,
0
]
},
{
"parameters": {
"modelId": {
"__rl": true,
"mode": "id",
"value": "claude-haiku-4-5"
},
"messages": {
"values": [
{
"content": "=Here is the conversation so far, oldest first. The last line is the new customer message. Answer it.\n\n{{ $json.transcript }}",
"role": "user"
}
]
},
"options": {
"system": "You are the front desk for Blue Summit Home Services, an HVAC and plumbing company in Denver, CO. Customers text the office number or use the website chat, and you answer.\n\nHow to write: plain texting register, like a real person at the office texting a customer. Short sentences. Contractions are fine. No emojis. No em dashes. No exclamation points. No corporate phrases like 'we appreciate your business' or 'reaching out'. Ask one question at a time. Keep every reply under 300 characters.\n\nBusiness facts: We do HVAC and plumbing repair, maintenance, and installs around Denver. The office is open 8am to 6pm, Monday through Saturday. Booking link: https://blue-summit.example.com/book\n\nWhat you can do: answer service questions, share ballpark price ranges, and offer the booking link when they want to move forward. Rough ranges you can share: AC tune-up $89 to $129, furnace repair $150 to $600, drain clearing $99 to $250, water heater replacement $1,400 to $2,600. Always say the office confirms the exact price. Never invent availability or promise a specific time.\n\nAnswer with strict JSON only, nothing before or after it: {\"reply\": \"the text to send the customer\", \"hot_lead\": true or false, \"needs_human\": true or false}. Set hot_lead to true when the customer wants work done soon or asks to book. Set needs_human to true for complaints, emergencies like a burst pipe or no heat in winter, or anything you are not sure about."
}
},
"id": "anthropic-front-desk",
"name": "The AI Front Desk Writes A Reply",
"type": "@n8n/n8n-nodes-langchain.anthropic",
"typeVersion": 1,
"position": [
880,
0
],
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const info = $('Pull Up This Conversation').first().json;\n\n// The model is told to answer in strict JSON, but read it defensively in case it wraps the JSON in text.\nconst raw = $json.content?.[0]?.text ?? $json.message?.content?.[0]?.text ?? $json.text ?? '';\nlet parsed = {};\ntry {\n parsed = JSON.parse(String(raw).replace(/^```json\\s*|```\\s*$/g, ''));\n} catch (e) {\n const match = String(raw).match(/\\{[\\s\\S]*\\}/);\n if (match) { try { parsed = JSON.parse(match[0]); } catch (e2) { parsed = {}; } }\n}\n\nlet reply = String(parsed.reply ?? '').trim();\nconst hotLead = parsed.hot_lead === true;\nlet needsHuman = parsed.needs_human === true;\n\n// No usable answer means a person takes it. And when a person is taking over,\n// the customer gets a short handoff line instead of the model's answer.\nif (!reply) needsHuman = true;\nif (needsHuman) reply = 'Let me get someone from the office to text you right back.';\n\nreturn [{ json: { ...info, reply, hotLead, needsHuman } }];"
},
"id": "code-read-answer",
"name": "Read The AI Answer",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1100,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.hotLead }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-hot-lead",
"name": "Ready To Book Soon?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1320,
0
]
},
{
"parameters": {
"method": "POST",
"url": "=https://services.leadconnectorhq.com/contacts/{{ $('Read The AI Answer').first().json.contactId }}/tags",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Version",
"value": "2021-07-28"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{ \"tags\": [\"hot-lead\"] }",
"options": {}
},
"id": "http-tag-hot-lead",
"name": "Tag Them Hot Lead In GoHighLevel",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1540,
-180
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "message",
"operation": "post",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "sales-team"
},
"text": "=This one is ready, jump in.\nName: {{ $('Read The AI Answer').first().json.name }}\nPhone: {{ $('Read The AI Answer').first().json.phone }}\nChannel: {{ $('Read The AI Answer').first().json.channel }}\nThey said: {{ $('Read The AI Answer').first().json.messageText }}\nThe AI replied: {{ $('Read The AI Answer').first().json.reply }}",
"otherOptions": {}
},
"id": "slack-hot-lead",
"name": "Tell Sales To Jump In",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.5,
"position": [
1760,
-180
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $('Read The AI Answer').first().json.needsHuman }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-needs-human",
"name": "Does This Need A Person?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1980,
0
]
},
{
"parameters": {
"method": "POST",
"url": "=https://services.leadconnectorhq.com/contacts/{{ $('Read The AI Answer').first().json.contactId }}/tags",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Version",
"value": "2021-07-28"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{ \"tags\": [\"needs-a-human\"] }",
"options": {}
},
"id": "http-tag-needs-human",
"name": "Tag Them Needs A Human",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2200,
-180
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "message",
"operation": "post",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "sales-team"
},
"text": "=A customer needs a person on this thread.\nName: {{ $('Read The AI Answer').first().json.name }}\nPhone: {{ $('Read The AI Answer').first().json.phone }}\nChannel: {{ $('Read The AI Answer').first().json.channel }}\nThey said: {{ $('Read The AI Answer').first().json.messageText }}\nThe AI told them someone from the office will text right back. Pick it up in GoHighLevel.",
"otherOptions": {}
},
"id": "slack-needs-human",
"name": "Tell The Office To Take Over",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.5,
"position": [
2420,
-180
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "POST",
"url": "https://services.leadconnectorhq.com/conversations/messages",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Version",
"value": "2021-07-28"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ type: 'SMS', contactId: $('Read The AI Answer').first().json.contactId, message: $('Read The AI Answer').first().json.reply }) }}",
"options": {}
},
"id": "http-send-reply",
"name": "Text The Reply To The Customer",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2640,
0
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const info = $('Read The AI Answer').first().json;\nconst staticData = $getWorkflowStaticData('global');\nstaticData.conversations = staticData.conversations ?? {};\nconst history = staticData.conversations[info.contactId] ?? [];\n\nhistory.push({ role: 'customer', text: info.messageText });\nhistory.push({ role: 'frontdesk', text: info.reply });\n\n// Keep the last 10 turns per contact.\nstaticData.conversations[info.contactId] = history.slice(-20);\n\nreturn [{ json: { ok: true, contactId: info.contactId, reply: info.reply } }];"
},
"id": "code-save-history",
"name": "Save This Conversation",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2860,
0
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ ok: true }) }}",
"options": {}
},
"id": "respond-done",
"name": "All Done",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
3080,
0
]
}
],
"connections": {
"Customer Sent A Message": {
"main": [
[
{
"node": "Read The Message",
"type": "main",
"index": 0
}
]
]
},
"Read The Message": {
"main": [
[
{
"node": "Did The Customer Send This?",
"type": "main",
"index": 0
}
]
]
},
"Did The Customer Send This?": {
"main": [
[
{
"node": "Pull Up This Conversation",
"type": "main",
"index": 0
}
],
[
{
"node": "All Done",
"type": "main",
"index": 0
}
]
]
},
"Pull Up This Conversation": {
"main": [
[
{
"node": "The AI Front Desk Writes A Reply",
"type": "main",
"index": 0
}
]
]
},
"The AI Front Desk Writes A Reply": {
"main": [
[
{
"node": "Read The AI Answer",
"type": "main",
"index": 0
}
]
]
},
"Read The AI Answer": {
"main": [
[
{
"node": "Ready To Book Soon?",
"type": "main",
"index": 0
}
]
]
},
"Ready To Book Soon?": {
"main": [
[
{
"node": "Tag Them Hot Lead In GoHighLevel",
"type": "main",
"index": 0
}
],
[
{
"node": "Does This Need A Person?",
"type": "main",
"index": 0
}
]
]
},
"Tag Them Hot Lead In GoHighLevel": {
"main": [
[
{
"node": "Tell Sales To Jump In",
"type": "main",
"index": 0
}
]
]
},
"Tell Sales To Jump In": {
"main": [
[
{
"node": "Does This Need A Person?",
"type": "main",
"index": 0
}
]
]
},
"Does This Need A Person?": {
"main": [
[
{
"node": "Tag Them Needs A Human",
"type": "main",
"index": 0
}
],
[
{
"node": "Text The Reply To The Customer",
"type": "main",
"index": 0
}
]
]
},
"Tag Them Needs A Human": {
"main": [
[
{
"node": "Tell The Office To Take Over",
"type": "main",
"index": 0
}
]
]
},
"Tell The Office To Take Over": {
"main": [
[
{
"node": "Text The Reply To The Customer",
"type": "main",
"index": 0
}
]
]
},
"Text The Reply To The Customer": {
"main": [
[
{
"node": "Save This Conversation",
"type": "main",
"index": 0
}
]
]
},
"Save This Conversation": {
"main": [
[
{
"node": "All Done",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
anthropicApihttpHeaderAuthslackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Ai-Conversation-Agent. Uses anthropic, httpRequest, slack. Webhook trigger; 17 nodes.
Source: https://github.com/mcruz1799/automation-examples/blob/main/claude-code/02-automation-file-factory/skills/n8n/section-templates/ai-conversation-agent.json — 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.
Airtable Operations System: Leads, AI Agent, Outreach, Sync, Canva, Make/Zapier Bridge. Uses airtable, anthropic, slack, agent. Webhook trigger; 82 nodes.
This n8n workflow orchestrates a powerful suite of AI Agents and automations to manage and optimize various aspects of an e-commerce operation, particularly for platforms like Shopify. It leverages La
Fully automates your service order pipeline from incoming booking to supplier confirmation — with built-in SLA enforcement and automatic escalation if a supplier goes silent. 📥 Receives orders via web
This workflow automatically processes new free-trial / lead sign-ups in real time: Catches a webhook from any source (Webflow form, Intercom, custom agent, etc.) Filters out personal / disposable / .e
Public-facing professionals (developer advocates, founders, marketers, content creators) who get bombarded with LinkedIn messages that aren't actually for them - support requests when you're in market