Dental Receptionist voice agent A developer built a dental receptionist voice agent using n8n and AI tools. The agent handles appointment scheduling, CRM lookups, and urgency checks for MN Dental, operating within specified clinic hours and timezone. | { | | | "name": "MN dental receptionist speed to lead", | | | "nodes": | | | { | | | "parameters": { | | | "httpMethod": "POST", | | | "path": "00000000-0000-4000-8000-000000000001", | | | "responseMode": "responseNode", | | | "options": {} | | | }, | | | "type": "n8n-nodes-base.webhook", | | | "typeVersion": 2.1, | | | "position": | | | -240, | | | -32 | | | , | | | "id": "00000000-0000-4000-8000-000000000002", | | | "name": "Webhook", | | | "webhookId": "00000000-0000-4000-8000-000000000001" | | | }, | | | { | | | "parameters": { | | | "promptType": "define", | | | "text": "=Request data:\n{{ JSON.stringify $json.body }}", | | | "options": { | | | "systemMessage": "= Role\n\nYou are the backend AI agent for MN Dental.\n\nYour responsibility is to receive requests from the voice agent, determine which backend tool should be used, execute the appropriate tool s , and return structured results.\n\nAlways use the think tool before making any decision.\n\nThe clinic operates in the Asia/Karachi timezone.\n\nAll dates and times exchanged with backend tools must be in ISO 8601 format.\n\n---\n\n Available Tools\n\nYou have access to the following tools:\n\n think – Must be called before every request.\n services offered – Checks the Services Offered document and returns whether the requested treatment is available.\n crm lookup – Searches the CRM using the caller's phone number.\n lead urgency checker – Checks the Lead Urgency document for the requested service.\n get availability – Retrieves available appointment slots.\n create appointment – Books an appointment.\n get appointment – checks appointment from calender\n cancel appointment – Cancels an appointment.\n reschedule appointment – Updates an existing appointment.\n log patient details – Logs the completed call to the CRM.\n\n---\n\n Tool Rules\n\n think\n\n Must be called on every request.\n Use it to determine which backend tool s are required.\n\n---\n\n services offered\n\nInput:\n\n Requested dental service.\n\nAction:\n\n Check the Services Offered document.\n\nReturn:\n\nIf offered:\n\n json\n{\n \"serviceAvailable\": true\n}\n \n\nIf not offered:\n\n json\n{\n \"serviceAvailable\": false\n}\n \n\nDo not perform any additional actions if the service is unavailable.\n\n---\n\n crm lookup\n\nInput:\n\n Patient phone number.\n\nSearch the CRM.\n\nIf the patient exists:\n\n json\n{\n \"existingPatient\": true,\n \"patientName\": \"...\",\n \"phoneNumber\": \"...\",\n \"patientDetails\": { }\n}\n \n\nIf the patient does not exist:\n\n json\n{\n \"existingPatient\": false\n}\n \n\nOnly identify whether the patient exists and return any stored patient information.\n\nDo not modify CRM records.\n\n---\n\n lead urgency checker\n\nInput:\n\n Requested service.\n\nAction:\n\nConsult the Lead Urgency document.\n\nReturn every screening question required for that service.\n\nExample:\n\n json\n{\n \"questions\": \n \"...\",\n \"...\",\n \"...\"\n \n}\n \n\nAfter the voice agent submits the patient's answers:\n\nEvaluate the urgency according to the document.\n\nReturn only:\n\n json\n{\n \"urgency\": \"Urgent\"\n}\n \n\nor\n\n json\n{\n \"urgency\": \"Non-Urgent\"\n}\n \n\nNever determine urgency using your own reasoning.\n\nOnly use the Lead Urgency document.\n\n---\n Clinic Hours\n\nThe clinic operates during the following business hours:\n\n Monday to Friday\n 9:00 AM to 5:00 PM\n Timezone: Asia/Karachi PKT \n\nRules:\n\n Do not return, create, reschedule, or suggest appointments outside business hours.\n Do not return appointments on Saturdays or Sundays.\n For urgent cases, search for the earliest available same-day appointment.\n For non-urgent cases, appointments must be scheduled within the next 14 calendar days only . Do not offer or create appointments beyond this window.\n\n---\n\n get availability\n\nInput:\n\n ISO 8601 timestamp.\n\nRules:\n\n Search availability only within clinic hours Monday to Friday, 9:00 AM to 5:00 PM, Asia/Karachi .\n Never return weekend appointments.\n For urgent cases, search same-day availability only.\n For non-urgent cases, search availability within the next 14 calendar days only .\n Do not return or suggest appointment slots beyond the 14-day booking window for non-urgent cases.\n Always attempt to return exactly two available appointment slots.\n If fewer than two are available, return all available slots.\n\nAll returned dates and times must be in ISO 8601 format using the Asia/Karachi timezone.\n\n\nInput:\n\nISO 8601 timestamp.\n\nSearch for available appointments within clinic hours.\n\nClinic Hours:\n\nMonday-Friday\n\n9:00 AM – 5:00 PM\n\nAsia/Karachi timezone.\n\nAlways attempt to return exactly two available appointment slots.\n\nIf fewer than two are available, return whatever is available.\n\nReturn:\n\n json\n{\n \"availableSlots\": \n \"2026-07-15T10:00:00+05:00\",\n \"2026-07-15T11:30:00+05:00\"\n \n}\n \n\nAll returned timestamps must be ISO 8601.\n\n---\n\n create appointment\n\nBooks the selected appointment.\n\nMay only be called once per request.\n\n get appointment\n\nGets patient’s appointment details from calender\n\n cancel appointment\n\nCancels the requested appointment.\n\nMay only be called once per request.\n\n---\n\n reschedule appointment\n\nUpdates an existing appointment.\n\nMay only be called once per request.\n\n---\n\n log patient details\n\nCalled only after the voice conversation has been completed.\n\nLog:\n\n Patient name\n Phone number\n Existing or new patient\n Requested service\n Screening questions\n Screening answers\n Urgency classification\n Appointment date\n Appointment status\n Call outcome\n\nMay only be called once.\n\n---\n\n Workflow\n\n Booking\n\n1. Call think .\n2. Check services offered .\n3. If the service is unavailable, return serviceAvailable: false .\n4. If available, perform crm lookup .\n5. Return whether the patient exists and any stored details.\n6. Run lead urgency checker and return all screening questions.\n7. After receiving the patient's answers, evaluate urgency.\n8. If Urgent, check same-day availability.\n9. If Non-Urgent, check availability within the next 14 days.\n10. Return two available appointment slots.\n11. Create the appointment.\n12. Log the completed interaction.\n\n---\n\n Rescheduling\n\n1. Call think .\n2. Retrieve the patient's appointment. get appointment \n3. Check availability.\n4. Return two appointment options.\n5. Reschedule the selected appointment.\n6. Log the interaction.\n\n---\n\n Cancellation\n\n1. Call think .\n2. Retrieve the appointment. get appointment \n3. Cancel the appointment.\n4. Log the interaction.\n\n---\n\n Constraints\n\n Always call think first.\n Never call create appointment more than once.\n Never call cancel appointment more than once.\n Never call reschedule appointment more than once.\n Never call log patient details more than once.\n Never call get appointment more than once\n Never modify CRM records during lookup.\n Return all timestamps in ISO 8601 format using the Asia/Karachi timezone.\n Only determine urgency from the Lead Urgency document.\n Only determine service availability from the Services Offered document.\n" | | | } | | | }, | | | "type": "@n8n/n8n-nodes-langchain.agent", | | | "typeVersion": 3, | | | "position": | | | 208, | | | -32 | | | , | | | "id": "00000000-0000-4000-8000-000000000003", | | | "name": "AI Agent" | | | }, | | | { | | | "parameters": { | | | "model": { | | | " rl": true, | | | "mode": "list", | | | "value": "ism-0.3-sibt" | | | }, | | | "builtInTools": {}, | | | "options": {} | | | }, | | | "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", | | | "typeVersion": 1.3, | | | "position": | | | -352, | | | 176 | | | , | | | "id": "00000000-0000-4000-8000-000000000004", | | | "name": "OpenAI Chat Model", | | | "credentials": { | | | "openAiApi": { | | | "id": "ismAIs3b74cRQsaf", | | | "name": "Credential 2" | | | } | | | } | | | }, | | | { | | | "parameters": {}, | | | "type": "@n8n/n8n-nodes-langchain.toolThink", | | | "typeVersion": 1.1, | | | "position": | | | -208, | | | 176 | | | , | | | "id": "00000000-0000-4000-8000-000000000005", | | | "name": "Think" | | | }, | | | { | | | "parameters": { | | | "operation": "get", | | | "documentURL": "https://example1.com", | | | "simple": false | | | }, | | | "type": "n8n-nodes-base.googleDocsTool", | | | "typeVersion": 2, | | | "position": | | | -64, | | | 224 | | | , | | | "id": "00000000-0000-4000-8000-000000000006", | | | "name": "services offered", | | | "credentials": { | | | "googleDocsOAuth2Api": { | | | "id": "ZGkmBUp9K7XI0a3a", | | | "name": "Credential 4" | | | } | | | } | | | }, | | | { | | | "parameters": { | | | "operation": "get", | | | "documentURL": "https://example2.com", | | | "simple": false | | | }, | | | "type": "n8n-nodes-base.googleDocsTool", | | | "typeVersion": 2, | | | "position": | | | 96, | | | 224 | | | , | | | "id": "00000000-0000-4000-8000-000000000007", | | | "name": "lead urgency checker", | | | "credentials": { | | | "googleDocsOAuth2Api": { | | | "id": "ZGkmBUp9K7XI0a3a", | | | "name": "Credential 4" | | | } | | | } | | | }, | | | { | | | "parameters": { | | | "documentId": { | | | " rl": true, | | | "value": "6ctDXv-ydPvbmefhKWAKM6DgJE2h4H7ZaxoyYZExcugY", | | | "mode": "list", | | | "cachedResultName": "Resource 1", | | | "cachedResultUrl": "https://example3.com" | | | }, | | | "sheetName": { | | | " rl": true, | | | "value": "zgk=4", | | | "mode": "list", | | | "cachedResultName": "Resource 2", | | | "cachedResultUrl": "https://example4.com" | | | }, | | | "filtersUI": { | | | "values": | | | { | | | "lookupColumn": "Phone", | | | "lookupValue": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'values0 Value', The patient's phone number was used to call. , 'string' }}" | | | } | | | | | | }, | | | "options": {} | | | }, | | | "type": "n8n-nodes-base.googleSheetsTool", | | | "typeVersion": 4.7, | | | "position": | | | 240, | | | 224 | | | , | | | "id": "00000000-0000-4000-8000-000000000008", | | | "name": "crm lookup", | | | "credentials": { | | | "googleSheetsOAuth2Api": { | | | "id": "QhA0EBqUEsRNi73h", | | | "name": "Credential 6" | | | } | | | } | | | }, | | | { | | | "parameters": { | | | "calendar": { | | | " rl": true, | | | "value": "iaodyqlzyv01@bowel.shz", | | | "mode": "list", | | | "cachedResultName": "Resource 3" | | | }, | | | "additionalFields": {} | | | }, | | | "type": "n8n-nodes-base.googleCalendarTool", | | | "typeVersion": 1.3, | | | "position": | | | 400, | | | 224 | | | , | | | "id": "00000000-0000-4000-8000-000000000009", | | | "name": "create appointment", | | | "credentials": { | | | "googleCalendarOAuth2Api": { | | | "id": "I0hlR3hP1V2IcEvq", | | | "name": "Credential 8" | | | } | | | } | | | }, | | | { | | | "parameters": { | | | "operation": "getAll", | | | "calendar": { | | | " rl": true, | | | "value": "iaodyqlzyv01@bowel.shz", | | | "mode": "list", | | | "cachedResultName": "Resource 3" | | | }, | | | "timeMax": "={{ $now.plus { week: 2 } }}", | | | "options": {} | | | }, | | | "type": "n8n-nodes-base.googleCalendarTool", | | | "typeVersion": 1.3, | | | "position": | | | 560, | | | 224 | | | , | | | "id": "00000000-0000-4000-8000-00000000000a", | | | "name": "get availability", | | | "credentials": { | | | "googleCalendarOAuth2Api": { | | | "id": "I0hlR3hP1V2IcEvq", | | | "name": "Credential 8" | | | } | | | } | | | }, | | | { | | | "parameters": { | | | "operation": "getAll", | | | "calendar": { | | | " rl": true, | | | "value": "iaodyqlzyv01@bowel.shz", | | | "mode": "list", | | | "cachedResultName": "Resource 3" | | | }, | | | "timeMax": "={{ $now.plus { week: 2 } }}", | | | "options": {} | | | }, | | | "type": "n8n-nodes-base.googleCalendarTool", | | | "typeVersion": 1.3, | | | "position": | | | 704, | | | 224 | | | , | | | "id": "00000000-0000-4000-8000-00000000000b", | | | "name": "get appointment", | | | "credentials": { | | | "googleCalendarOAuth2Api": { | | | "id": "I0hlR3hP1V2IcEvq", | | | "name": "Credential 8" | | | } | | | } | | | }, | | | { | | | "parameters": { | | | "operation": "appendOrUpdate", | | | "documentId": { | | | " rl": true, | | | "value": "6ctDXv-ydPvbmefhKWAKM6DgJE2h4H7ZaxoyYZExcugY", | | | "mode": "list", | | | "cachedResultName": "Resource 1", | | | "cachedResultUrl": "https://example3.com" | | | }, | | | "sheetName": { | | | " rl": true, | | | "value": "zgk=4", | | | "mode": "list", | | | "cachedResultName": "Resource 2", | | | "cachedResultUrl": "https://example4.com" | | | }, | | | "columns": { | | | "mappingMode": "defineBelow", | | | "value": { | | | "Phone": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Phone using to match ', Phone number by which patient called , 'string' }}", | | | "Name": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Name', Name of the patient , 'string' }}", | | | "Appointment date": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Appointment date', Date of booked appointment , 'string' }}", | | | "Requested service": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Requested service', Service requested by the patient , 'string' }}", | | | "Existing or new patient": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Existing or new patient', New or existing patient in CRM , 'string' }}", | | | "Screening questions": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Screening questions', Urgency determining questions , 'string' }}", | | | "Screening answers": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Screening answers', Patient's answers to urgency determining questions , 'string' }}", | | | "Urgency classification": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Urgency classification', Urgent or not urgent , 'string' }}", | | | "Appointment status": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Appointment status', Status of the appointment , 'string' }}", | | | "Call outcome": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Call outcome', Outcome of the call , 'string' }}", | | | "Transcript": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Transcript', Transcript of the call , 'string' }}", | | | "Summary": "={{ / n8n-auto-generated-fromAI-override / $fromAI 'Summary', Summary of the call , 'string' }}" | | | }, | | | "matchingColumns": | | | "Phone" | | | , | | | "schema": | | | { | | | "id": "Name", | | | "displayName": "Name", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Phone", | | | "displayName": "Phone", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Requested service", | | | "displayName": "Requested service", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Existing or new patient", | | | "displayName": "Existing or new patient", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Screening questions", | | | "displayName": "Screening questions", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Screening answers", | | | "displayName": "Screening answers", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Urgency classification", | | | "displayName": "Urgency classification", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Appointment date", | | | "displayName": "Appointment date", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Appointment status", | | | "displayName": "Appointment status", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Call outcome", | | | "displayName": "Call outcome", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Transcript", | | | "displayName": "Transcript", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | }, | | | { | | | "id": "Summary", | | | "displayName": "Summary", | | | "required": false, | | | "defaultMatch": false, | | | "display": true, | | | "type": "string", | | | "canBeUsedToMatch": true, | | | "removed": false | | | } | | | , | | | "attemptToConvertTypes": false, | | | "convertFieldsToString": false | | | }, | | | "options": {} | | | }, | | | "type": "n8n-nodes-base.googleSheetsTool", | | | "typeVersion": 4.7, | | | "position": | | | 864, | | | 224 | | | , | | | "id": "00000000-0000-4000-8000-00000000000c", | | | "name": "log patient details", | | | "credentials": { | | | "googleSheetsOAuth2Api": { | | | "id": "QhA0EBqUEsRNi73h", | | | "name": "Credential 6" | | | } | | | } | | | }, | | | { | | | "parameters": { | | | "options": {} | | | }, | | | "type": "n8n-nodes-base.respondToWebhook", | | | "typeVersion": 1.4, | | | "position": | | | 720, | | | -32 | | | , | | | "id": "00000000-0000-4000-8000-00000000000d", | | | "name": "Respond to Webhook" | | | } | | | , | | | "pinData": { | | | "Webhook": | | | { | | | "json": { | | | "headers": { | | | "host": "transform-swapping-casket.ngrok-free.dev", | | | "user-agent": "ElevenLabs/1.0", | | | "content-length": "754", | | | "accept": " / ", | | | "accept-encoding": "gzip", | | | "content-type": "application/json", | | | "x-forwarded-for": "34.59.11.47", | | | "x-forwarded-host": "transform-swapping-casket.ngrok-free.dev", | | | "x-forwarded-proto": "https" | | | }, | | | "params": {}, | | | "query": {}, | | | "body": { | | | "startTime": "2026-06-26T16:00:00", | | | "patient name": "Miran Noor", | | | "phone number": "+46405550101", | | | "Existing or new patient": "New", | | | "Requested dental service": "Dental implant", | | | "Screening questions": "Do you have any pain or discomfort? Is the pain constant or does it come and go? How long have you been experiencing this pain? Is the pain sharp, dull, throbbing, or a different sensation? Is there any swelling or bleeding in the affected area? Have you tried any pain relief methods, and if so, were they effective?", | | | "Screening answers": "Slight pain, comes and goes, started yesterday, dull, no swelling or bleeding, paracetamol worked.", | | | "Urgency classification": "Urgent", | | | "Appointment status": "Confirmed", | | | "Call outcome": "Appointment booked" | | | }, | | | "webhookUrl": "https://example5.com", | | | "executionMode": "production" | | | } | | | } | | | , | | | "AI Agent": | | | { | | | "json": { | | | "output": "The dental implant service is available. The patient Miran Noor is new and was not found in the CRM. The urgency classification based on the patient's answers is Urgent. A same-day appointment on 2026-06-26 at 16:00 PKT was found and successfully booked. The appointment details have been logged.\n\nIf you need any further assistance, please let me know." | | | } | | | } | | | | | | }, | | | "connections": { | | | "Webhook": { | | | "main": | | | | | | { | | | "node": "AI Agent", | | | "type": "main", | | | "index": 0 | | | } | | | | | | | | | }, | | | "OpenAI Chat Model": { | | | "ai languageModel": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai languageModel", | | | "index": 0 | | | } | | | | | | | | | }, | | | "Think": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "services offered": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "lead urgency checker": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "crm lookup": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "create appointment": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "get availability": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "get appointment": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "log patient details": { | | | "ai tool": | | | | | | { | | | "node": "AI Agent", | | | "type": "ai tool", | | | "index": 0 | | | } | | | | | | | | | }, | | | "AI Agent": { | | | "main": | | | | | | { | | | "node": "Respond to Webhook", | | | "type": "main", | | | "index": 0 | | | } | | | | | | | | | } | | | }, | | | "active": false, | | | "settings": { | | | "executionOrder": "v1" | | | }, | | | "versionId": "00000000-0000-4000-8000-00000000000e", | | | "meta": { | | | "templateCredsSetupCompleted": true, | | | "instanceId": "fbdac00ffaa7e7238f982cc513c9bf356af4186007793f48b604711711d77366" | | | }, | | | "id": "xaUbRLYCr80Perc3", | | | "tags": | | | } |