Automated customer service with Claude API + n8n (for clinics that don't sleep)
Dental clinics get messages constantly. Someone wants info about treatment. Someone wants to book. Someone sends “what’s the price?”. Half arrive after the clinic closes.
I solved this for a clinic in São Paulo. A bot running 24/7 that qualifies leads, collects info, and hands off to a human when needed. Result: 60% of leads arrive already categorized. The support team saves 3 hours a day answering repetitive questions.
I’ll show you how to build it.
What you’re going to build
An n8n workflow that:
- Receives WhatsApp messages
- Passes them to Claude for analysis
- Claude responds or qualifies as “needs human”
- If qualified, passes to support queue
Cost per conversation: $0.003 (May 2026). If you process 1000 conversations per month, that’s $3. The team’s time savings? About $12 per day.
Initial setup
You’ll need:
- Claude API account (with balance)
- n8n running (self-hosted or n8n.cloud)
- WhatsApp Business account or Twilio WhatsApp
- A database (can be Supabase, Firebase, or PostgreSQL)
I’m assuming you already have n8n running. If not, quick setup: docker run -it -p 5678:5678 n8nio/n8n.
The prompt that works for a clinic
This is the heart of the system. Everything depends on a well-crafted prompt:
You are a dental clinic support assistant.
Your job is: receive messages from possible patients and qualify them.
CLINIC CONTEXT:
- Location: São Paulo, south zone
- Specialties: cosmetic, implants, cleaning
- Hours: Mon-Fri, 8am-6pm
- WhatsApp booking link: [calendar link]
YOUR MISSION:
1. Answer simple questions (hours, location, procedures)
2. Collect info: name, procedure type, phone
3. When someone wants to book, give them the calendar link
4. If conversation gets complex, hand off to human
WHEN TO HAND OFF TO HUMAN:
- Patient is in pain/emergency
- Needs detailed diagnosis
- Wants to negotiate price
- Is unhappy
- Asks health questions you're unsure about
RULES:
- Always be friendly, never robotic
- If you don't know, say honestly
- Don't invent procedure info
- If patient says "pain", mark as EMERGENCY
ALWAYS RESPOND IN PORTUGUESE.
End each response with a meta:
[META: interaction_type] where type can be: INFORMATION, BOOKING, QUALIFIED, EMERGENCY
Each meta defines what happens with the conversation.
n8n workflow step by step
Start with a blank workflow in n8n.
Step 1: WhatsApp Trigger
Add a “Webhook” node configured to receive POST from your WhatsApp provider.
{
"from": "5511987654321",
"body": "What's the price of cleaning?"
}
Step 2: Code to extract data
Create a Function node that processes the message:
const message = $input.all()[0].body.body;
const phone = $input.all()[0].body.from;
return {
message,
phone,
timestamp: new Date().toISOString(),
};
Step 3: Call Claude API
Add an HTTP Request node configured like this:
Method: POST
URL: https://api.anthropic.com/v1/messages
Authorization Header: Bearer {your_api_key}
Body (JSON):
{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 300,
"messages": [
{
"role": "user",
"content": "{{$node.ProcessMessage.json.message}}"
}
],
"system": "[your prompt from above]"
}
Claude responds. The node returns something like:
{
"content": [
{
"type": "text",
"text": "Hi! Cleaning costs R$200 and takes 30 minutes. Want to book? [link]"
}
]
}
Step 4: Extract the meta
Use regex to pull that [META: ...]:
const response = $input.all()[0].json.content[0].text;
const metaMatch = response.match(/\[META: (\w+)\]/);
const meta = metaMatch ? metaMatch[1] : "UNKNOWN";
return { meta, response };
Step 5: Switch based on meta
Use a Switch node:
- If
meta === "EMERGENCY": go to “Human Handoff - Urgent” - If
meta === "QUALIFIED": go to “Qualified - Create Lead” - If
meta === "BOOKING": go to “Sent Link” - If
meta === "INFORMATION": respond and continue
Step 6: Respond on WhatsApp
HTTP Request node to send back:
Method: POST
URL: [your WhatsApp webhook]
Body:
{
"to": "{{$node.ProcessMessage.json.phone}}",
"body": "{{$node.ExtractMeta.json.response}}"
}
Step 7: Save to Supabase
Before responding, save everything:
Method: POST
URL: https://your-supabase.supabase.co/rest/v1/messages
Body:
{
"phone": "{{$node.ProcessMessage.json.phone}}",
"incoming_message": "{{$node.ProcessMessage.json.message}}",
"response": "{{$node.ExtractMeta.json.response}}",
"meta": "{{$node.ExtractMeta.json.meta}}",
"timestamp": "{{$node.ProcessMessage.json.timestamp}}"
}
Step 8: Notify team if handoff
If meta === "EMERGENCY" or meta === "QUALIFIED", send to Slack/email:
[NEW LEAD - CLINIC]
Name: {{extracted from history}}
Type: {{meta}}
Message: {{original message}}
Reply at: https://clinic.com/dashboard/leads/{{id}}
Real cost per conversation
In May 2026, Claude 3.5 Sonnet pricing:
- Input: $3 per 1 million tokens
- Output: $15 per 1 million tokens
A typical 5-exchange conversation (5 user messages + 5 bot replies):
- Input: ~400 tokens per conversation (prompt + message)
- Output: ~150 tokens per reply = 750 total
Math:
- (400 input tokens / 1M) * $3 = $0.0012
- (750 output tokens / 1M) * $15 = $0.01125
- Total: ~$0.0124 per conversation
So about $0.012 per conversation.
If 1000 conversations per month: ~$12. Team’s time saved? About 30 hours. Support hourly cost: $20/hour = $600 saved. ROI: 50x.
How to avoid hallucination
The biggest risk is Claude inventing info about procedures the clinic doesn’t offer. Three techniques:
1. Restrictive context system
You KNOW ONLY:
- Cleaning: R$200
- Whitening: R$500
- Implant: consultation needed
Any question about other procedure: "We don't offer that service.
Want to know what we do? [link]"
2. Response validation
Before sending, use another Claude call to validate:
Generated response: "Implant costs R$3000"
Validate: is this in our procedures database? YES/NO
If NO: reject and replace with "We don't have that info available"
3. Human in the loop for critical info
If meta is “EMERGENCY” or “CUSTOM_PROCEDURE”, always hand off to human. Don’t take the risk.
Metrics that matter
After the system runs for a week, analyze:
Qualification rate: % of conversations that came out “qualified” (name + phone + procedure type) = your bot’s success rate.
At the clinic I set up: 62% qualification. That means 62% of conversations that went in came out with info the team could use.
Escalation rate: % of messages that went to human. Should be between 10-25%. Above 40% means your prompt is escalating too much. Below 5% might mean stuff is slipping through.
Average response time: how fast does your bot respond? Should be seconds. If minutes, something’s slow.
Completion rate: how many conversations got enough info for follow-up? Could the clinic actually book based on what the bot collected?
Extra integrations to consider
- Google Calendar: bot collects desired date/time, checks availability, books directly
- Stripe: customer wants to pay now? Bot generates invoice, charges via link
- Slack: bot sends real-time notifications to team, don’t wait for dashboard checks
- Custom CRM: each qualified conversation becomes a new contact in your CRM
Prompt tuning: iteration is key
The first prompt will be okay. Not great. Run for a week, see real conversations that failed, adjust.
Examples of tweaks:
- Week 1: bot escalating too much. You make the prompt more assertive.
- Week 2: bot can’t handle price questions well. You structure pricing section better.
- Week 3: patients want to book but link doesn’t arrive right. You simplify the call-to-action.
Each iteration improves.
Real operational costs
- Claude API: $12-30/month (depending on volume)
- n8n.cloud: $0 (free) or $4/month (pro)
- WhatsApp Business: $0.07 per message (sent by you)
- Supabase: $0 (free) or $5/month
Total per month: $12-40.
Team’s time savings: $600+.
Checklist: clinic chatbot deployment
- Prompt is clinic-specific (not generic)?
- Three meta types defined (INFORMATION, QUALIFIED, EMERGENCY)?
- Each response includes meta at end (for routing)?
- Supabase/database ready to save conversations?
- WhatsApp webhook tested (can receive messages)?
- Claude API node authenticated and calling correctly?
- Switch logic routing correctly to different metas?
- Support team knows where to find new leads?
- Hallucination validation in place (for procedures)?
- You tested with 10-20 real messages before going live?
Security checklist for API integrations
When connecting Claude API to customer service tools, security matters:
- Never log customer messages (they’re private)
- Never store API responses in plain text
- Rate limit customer requests (prevent abuse)
- Validate input before sending to Claude (prevents injection attacks)
- Use environment variables for API keys, never hardcode
- Monitor unusual patterns (detect compromised keys)
A breached API key costs you money and customer trust. Spend 1 hour setting up security properly at the start. Saves you 100 hours of debugging later.
Measuring success
How do you know if Claude API + N8N customer service system is working?
Metrics to track: average response time, customer satisfaction (add a quick feedback button), percentage of issues resolved without human intervention.
If a customer submits a request at 3pm and Claude answers at 3:02pm with 85% accuracy, that’s working. If humans are needed 30% of the time, that’s also working (most systems need human escalation).
Red flag: if humans are needed 80% of the time. That means your system isn’t helping.
Track these metrics monthly and adjust the system.
Read also: n8n automations and webhooks | WhatsApp Business API for dental clinics | Pricing AI automation