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 →
{
"name": "Dental Clinic WhatsApp AI Bot",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "dental-whatsapp",
"responseMode": "lastNode",
"options": {}
},
"id": "webhook-trigger",
"name": "WhatsApp Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
250,
300
]
},
{
"parameters": {
"jsCode": "// Parse incoming WhatsApp message\n// Expects: { from: string, text: string, name: string, timestamp: string }\nconst body = $input.item.json;\n\n// Extract message text and sender\nconst message = body.text || body.message || body.body || '';\nconst sender = body.from || body.sender || body.wa_id || '';\nconst senderName = body.name || body.profile?.name || 'Patient';\n\n// Store conversation context (you'd use a DB in production)\n// For demo, we pass everything to the AI\nreturn {\n sender: sender,\n senderName: senderName,\n message: message,\n timestamp: new Date().toISOString()\n};"
},
"id": "parse-message",
"name": "Parse Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
450,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.deepseek.com/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{$env.DEEPSEEK_API_KEY}}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": []
},
"specifyBody": "json",
"jsonBody": "{\n \"model\": \"deepseek-chat\",\n \"temperature\": 0.3,\n \"max_tokens\": 300,\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a dental clinic receptionist AI for Bright Smile Dental (DEMO) in Salmiya, Kuwait. You speak Arabic and English. You help patients book appointments, answer questions about prices/services/hours/location, and handle inquiries.\\n\\nCLINIC INFO:\\n- Hours: Sat-Thu 9AM-9PM, Fri closed\\n- Location: Salem Al Mubarak St, Block 2, Salmiya\\n- Phone: +965 5555 1234\\n\\nPRICES (KWD):\\n- Check-up & Cleaning: 25\\n- Filling: 40-80\\n- Whitening: 120\\n- Braces Consultation: Free\\n- Root Canal: 150-250\\n\\nRESPOND IN JSON ONLY: {\\\"intent\\\": \\\"booking|question|greeting|other\\\", \\\"reply_ar\\\": \\\"Arabic response\\\", \\\"reply_en\\\": \\\"English response\\\", \\\"booking_details\\\": {\\\"date\\\": null, \\\"time\\\": null, \\\"type\\\": null, \\\"name\\\": null, \\\"phone\\\": null}}\"\n },\n {\n \"role\": \"user\",\n \"content\": \"={{ $json.message }}\"\n }\n ]\n}"
},
"id": "ai-process",
"name": "AI Classify & Respond",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
650,
300
]
},
{
"parameters": {
"jsCode": "// Parse DeepSeek response and format for WhatsApp reply\nconst aiResponse = $input.item.json;\nconst content = aiResponse.choices?.[0]?.message?.content || '{}';\n\nlet parsed;\ntry {\n // Clean markdown code blocks if present\n const cleaned = content.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n parsed = JSON.parse(cleaned);\n} catch(e) {\n parsed = { intent: 'other', reply_en: 'I am sorry, could you please rephrase that?', reply_ar: '\u0639\u0641\u0648\u0627\u060c \u0645\u0645\u0643\u0646 \u062a\u0639\u064a\u062f \u0627\u0644\u0633\u0624\u0627\u0644\u061f' };\n}\n\n// Choose language based on message content (simple heuristic)\nconst originalMsg = $('Parse Message').item.json.message || '';\nconst isArabic = /[\\u0600-\\u06FF]/.test(originalMsg);\nconst reply = isArabic ? parsed.reply_ar : parsed.reply_en;\n\nreturn {\n sender: $('Parse Message').item.json.sender,\n reply: reply,\n intent: parsed.intent,\n booking_details: parsed.booking_details || {}\n};"
},
"id": "format-reply",
"name": "Format Reply",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
850,
300
]
},
{
"parameters": {
"jsCode": "// In production, this node sends via WhatsApp Business API\n// For demo: just returns the formatted reply\n// Replace with actual WhatsApp API call (Twilio, WATI, etc.)\n\nconst reply = $input.item.json.reply;\nconst sender = $input.item.json.sender;\n\n// If using Twilio WhatsApp:\n// POST to https://api.twilio.com/2010-04-01/Accounts/{sid}/Messages.json\n// Body: { To: `whatsapp:${sender}`, From: 'whatsapp:+965xxxxxxxx', Body: reply }\n\n// If using WATI/Interakt/other WhatsApp API:\n// POST to their endpoint with your API key\n\nconsole.log(`Sending to ${sender}: ${reply}`);\n\nreturn {\n sent_to: sender,\n message: reply,\n status: 'sent',\n timestamp: new Date().toISOString()\n};"
},
"id": "send-whatsapp",
"name": "Send WhatsApp Reply",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1050,
300
]
},
{
"parameters": {
"jsCode": "// Save booking to Google Sheets (or your DB)\n// This runs only for booking intents\nconst booking = $input.item.json.booking_details;\n\n// If you connect Google Sheets node here:\n// Append row with: [timestamp, name, phone, date, time, type]\n\nconsole.log('Booking received:', JSON.stringify(booking));\n\nreturn {\n logged: true,\n booking: booking\n};"
},
"id": "log-booking",
"name": "Log Booking",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
850,
450
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"status\": \"ok\",\n \"reply\": $json.message,\n \"intent\": $json.intent || $('Format Reply').item.json.intent\n}"
},
"id": "webhook-response",
"name": "Webhook Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
1250,
300
]
}
],
"connections": {
"WhatsApp Webhook": {
"main": [
[
{
"node": "Parse Message",
"type": "main",
"index": 0
}
]
]
},
"Parse Message": {
"main": [
[
{
"node": "AI Classify & Respond",
"type": "main",
"index": 0
}
]
]
},
"AI Classify & Respond": {
"main": [
[
{
"node": "Format Reply",
"type": "main",
"index": 0
}
]
]
},
"Format Reply": {
"main": [
[
{
"node": "Send WhatsApp Reply",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Booking",
"type": "main",
"index": 0
}
]
]
},
"Send WhatsApp Reply": {
"main": [
[
{
"node": "Webhook Response",
"type": "main",
"index": 0
}
]
]
},
"Log Booking": {
"main": []
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"versionId": "1.0.0",
"active": false
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Dental Clinic WhatsApp AI Bot. Uses httpRequest. Webhook trigger; 7 nodes.
Source: https://github.com/DiyaHussein/deepseek-lead-bots/blob/main/dental-bot-n8n-workflow.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.
This workflow automates bulk email campaigns with built-in validation, deliverability protection, and smart send-time optimization.
Universal Lead Processing Workflow. Uses googleSheets, gmail, httpRequest, gmailTrigger. Webhook trigger; 34 nodes.
This workflow turns Feishu bot messages into a human-in-the-loop short-video production pipeline, using Tavily for web search, DeepSeek for topic and script generation, Jimeng AI for text-to-video, an
This workflow is designed to manage the assignment and validation of unique QR code coupons within a lead generation system with SuiteCRM.
This workflow acts as an instant SDR that replies to new inbound leads across multiple channels in real time. It first captures and normalizes all incoming lead data into a unified structure. The work