Rebook missed clinic appointments on WhatsApp
Every evening, patients who missed today's appointment get a kind WhatsApp message offering a new time.
How it works
- Read the Appointments sheet.
- Find today's appointments marked "no-show" that haven't been contacted.
- Send a WhatsApp template offering to rebook with the same doctor.
- Mark the row so the patient is never messaged twice.
Diagram
Code
JavaScript used in the Code step — already included in the template below.
// Appointments sheet columns: date (YYYY-MM-DD) | time | patient | phone | doctor | status | rebook_sent
// Keeps today's no-shows that haven't had a rebooking message yet.
const today = new Date().toISOString().slice(0, 10);
return $input.all()
.map((item) => item.json)
.filter((a) => String(a.date).slice(0, 10) === today)
.filter((a) => String(a.status).toLowerCase() === "no-show" && !a.rebook_sent && a.phone)
.map((a) => ({
json: {
row_number: a.row_number,
phone: String(a.phone).replace(/[^0-9]/g, ""),
patient: a.patient,
doctor: a.doctor,
time: a.time,
},
}));Build it
Pick your tool — same automation, step by step.
Copy and paste straight into an n8n canvas (Ctrl+V), or download and use Import from File. Then connect your own credentials and replace every YOUR_… placeholder.
Show code (199 lines)
{
"name": "Rebook missed clinic appointments on WhatsApp (Flowngn)",
"nodes": [
{
"parameters": {
"content": "## Rebook missed clinic appointments on WhatsApp\nEvery evening, patients who missed today's appointment get a kind WhatsApp message offering a new time.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
"height": 260,
"width": 340
},
"id": "2c52a72d-5332-4279-a57c-4e7c465d70f8",
"name": "Setup notes",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-420,
-60
]
},
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 20
}
]
}
},
"id": "2c52a72d-5332-4279-a57c-4e7c465d70f8",
"name": "Every day 20:00",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
0
]
},
{
"parameters": {
"operation": "read",
"documentId": {
"__rl": true,
"value": "YOUR_SPREADSHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Appointments",
"mode": "name"
},
"options": {}
},
"id": "2c52a72d-5332-4279-a57c-4e7c465d70f8",
"name": "Read appointments",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
300,
0
]
},
{
"parameters": {
"jsCode": "// Appointments sheet columns: date (YYYY-MM-DD) | time | patient | phone | doctor | status | rebook_sent\n// Keeps today's no-shows that haven't had a rebooking message yet.\nconst today = new Date().toISOString().slice(0, 10);\n\nreturn $input.all()\n .map((item) => item.json)\n .filter((a) => String(a.date).slice(0, 10) === today)\n .filter((a) => String(a.status).toLowerCase() === \"no-show\" && !a.rebook_sent && a.phone)\n .map((a) => ({\n json: {\n row_number: a.row_number,\n phone: String(a.phone).replace(/[^0-9]/g, \"\"),\n patient: a.patient,\n doctor: a.doctor,\n time: a.time,\n },\n }));"
},
"id": "2c52a72d-5332-4279-a57c-4e7c465d70f8",
"name": "Today's no-shows",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
600,
0
]
},
{
"parameters": {
"operation": "sendTemplate",
"phoneNumberId": "YOUR_PHONE_NUMBER_ID",
"recipientPhoneNumber": "={{ $json.phone }}",
"template": "YOUR_REBOOK_TEMPLATE|ar",
"components": {
"component": [
{
"type": "body",
"bodyParameters": {
"parameter": [
{
"type": "text",
"text": "={{ $json.patient }}"
},
{
"type": "text",
"text": "={{ $json.doctor }}"
}
]
}
}
]
}
},
"id": "2c52a72d-5332-4279-a57c-4e7c465d70f8",
"name": "Offer a new time",
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1,
"position": [
900,
0
]
},
{
"parameters": {
"operation": "update",
"documentId": {
"__rl": true,
"value": "YOUR_SPREADSHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Appointments",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"row_number": "={{ $('Today\\'s no-shows').item.json.row_number }}",
"rebook_sent": "={{ $now.toISODate() }}"
},
"matchingColumns": [
"row_number"
]
},
"options": {}
},
"id": "2c52a72d-5332-4279-a57c-4e7c465d70f8",
"name": "Mark as sent",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1200,
0
]
}
],
"connections": {
"Every day 20:00": {
"main": [
[
{
"node": "Read appointments",
"type": "main",
"index": 0
}
]
]
},
"Read appointments": {
"main": [
[
{
"node": "Today's no-shows",
"type": "main",
"index": 0
}
]
]
},
"Today's no-shows": {
"main": [
[
{
"node": "Offer a new time",
"type": "main",
"index": 0
}
]
]
},
"Offer a new time": {
"main": [
[
{
"node": "Mark as sent",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"meta": {
"templateCredsSetupCompleted": false
},
"tags": []
}In Make, create a new scenario and add these modules in order:
- Schedule the scenario: Every day 20:00
- Google Sheets › Search Rows
- Tools › Set variable / Iterator + Array aggregator (same logic as the Code step)
- WhatsApp Business Cloud › Send a Template Message
- Google Sheets › Update a Row
- Every module run uses Make operations — the free plan includes a monthly quota.
- Make's built-in functions (map, sum, formatDate…) can replace most Code steps; for complex logic use a code module.
- Module and step names can differ slightly as Make and Zapier update their apps.
In Zapier, create a new Zap and add these steps in order:
- Schedule by Zapier — Every day 20:00
- Google Sheets — Lookup Spreadsheet Rows (or Code by Zapier)
- Code by Zapier — Run JavaScript (paste the code from the Code section)
- WhatsApp — Send Template Message
- Google Sheets — Update Spreadsheet Row
- Zaps with more than two steps need a paid Zapier plan.
- Webhooks, Filters/Paths and Code by Zapier are premium features on some Zapier plans.
- Code by Zapier runs JavaScript: reuse the code shown above, reading inputs from inputData instead of $json.
- Module and step names can differ slightly as Make and Zapier update their apps.
Tips
- Keep the message warm, never blaming. Mention only the doctor's name, not the reason for the visit.
Related flows
Ask patients for feedback the day after their visit
The day after a visit, each patient gets a WhatsApp message with a short feedback form.
New patient forms to a sheet, with a reception alert
When a new patient fills your online form, save it to a sheet and alert reception on Telegram to call them.
Bosta delivery updates to customers on WhatsApp
Customers get a WhatsApp message when their Bosta shipment is picked up, out for delivery or delivered.