Appointment Reminders via SMS & WhatsApp
Overview
Missed appointments cost businesses across healthcare, professional services, and hospitality billions each year. Automated reminders sent via SMS or WhatsApp can reduce no-show rates by 20–30%, according to industry benchmarks.
DIDfarm lets you send reminders from the same local or national numbers your customers already recognise. Because messages come from a real phone number (not a short code), open rates are significantly higher and recipients can reply directly.
SMS vs WhatsApp for reminders
| Channel | Delivery | Rich content | Reply handling | Best for |
|---|---|---|---|---|
| SMS | Near-instant, works on all phones | Plain text only (160 chars / segment) | Keyword-based (YES / NO) | Universal reach, older demographics |
| Near-instant, requires WhatsApp app | Buttons, images, location pins | Quick-reply buttons + free text | Rich interactions, European & LATAM audiences |
Prerequisites
- A DIDfarm account with at least one active phone number.
- SMS enabled on the number (toggle in the portal under My Numbers → number settings).
- For WhatsApp: a WhatsApp-enabled number (request via the portal or contact support).
- A DIDfarm API key generated in the portal under Account → API Keys.
- A scheduling system in your application (cron, task queue, or external scheduler).
- A publicly reachable webhook endpoint to receive inbound replies.
Reminder Flow
A typical appointment reminder flow involves four stages. Here is the end-to-end lifecycle from booking to confirmation:
- Appointment booked — Your system stores the appointment details and calculates reminder times (e.g. 24 hours and 2 hours before).
- Reminder scheduled — A background job or cron task is queued for each reminder window.
- Reminder sent — At the scheduled time, your system calls the DIDfarm API to send an SMS or WhatsApp message with appointment details.
- Reply received — The patient or client replies YES, NO, or RESCHEDULE. Your webhook handler parses the reply and updates the booking accordingly.
Appointment booked
|
v
Schedule reminders (24h + 2h before)
|
v
Cron / queue fires at T-24h
|
v
POST /api/v1/sms/messages ──────> SMS / WhatsApp delivered
| |
v v
Cron fires at T-2h Patient replies YES / NO
| |
v v
Send 2nd reminder Webhook fires on your server
|
v
Update booking statusSchedule a Reminder
Queue reminders when the appointment is created
When a new appointment is saved, calculate the reminder timestamps and persist them in your database or job queue. Most businesses send two reminders: one 24 hours before and one 2 hours before the appointment.
function onAppointmentCreated(appointment) {
const reminders = [
{ offset: 24 * 60, label: '24h' }, // 24 hours before
{ offset: 2 * 60, label: '2h' }, // 2 hours before
];
for (const r of reminders) {
const sendAt = subtractMinutes(appointment.datetime, r.offset);
// Skip if the send time is already in the past
if (sendAt <= now()) continue;
scheduleJob('send-reminder', {
appointmentId: appointment.id,
recipientPhone: appointment.phone,
sendAt: sendAt,
label: r.label,
});
}
}Send the Reminder
Call the DIDfarm API when the scheduled time arrives
When your queue worker or cron job fires, send the reminder via the DIDfarm messaging API. Include the appointment date, time, location, and a clear call to action.
SMS reminder example
curl -X POST https://didfarm.com/api/v1/sms/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+31201234567",
"to": "+31612345678",
"body": "Reminder: Your appointment with Dr. van Berg is tomorrow, April 6 at 10:30 AM at Wijnhaven Clinic, Rotterdam. Reply YES to confirm or NO to cancel."
}'WhatsApp reminder example
curl -X POST https://didfarm.com/api/v1/whatsapp/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+31201234567",
"to": "+31612345678",
"template": "appointment_reminder",
"template_variables": {
"1": "Dr. van Berg",
"2": "April 6, 2026",
"3": "10:30 AM",
"4": "Wijnhaven Clinic, Rotterdam"
}
}'Node.js integration example
const axios = require('axios');
async function sendReminder(appointment) {
const localTime = formatInTimezone(
appointment.datetime,
appointment.timezone
);
const body = [
`Reminder: Your appointment with ${appointment.providerName}`,
`is on ${localTime.date} at ${localTime.time}`,
`at ${appointment.location}.`,
`Reply YES to confirm or NO to cancel.`,
].join(' ');
const response = await axios.post(
'https://didfarm.com/api/v1/sms/messages',
{
from: process.env.DIDFARM_NUMBER,
to: appointment.phone,
body: body,
},
{
headers: {
Authorization: `Bearer ${process.env.DIDFARM_API_KEY}`,
'Content-Type': 'application/json',
},
}
);
// Store the message ID for delivery tracking
await db.reminders.update(appointment.reminderId, {
messageId: response.data.id,
status: 'sent',
sentAt: new Date(),
});
}201 status with the message ID. Store this ID to correlate delivery status webhooks later.
Handle Replies
Process inbound messages via your webhook
When a recipient replies to your reminder, DIDfarm sends an HTTP POST to the webhook URL configured on your number. Parse the message body for keywords to determine the patient's intent.
{
"id": "msg_8f3a2b1c",
"from": "+31612345678",
"to": "+31201234567",
"body": "YES",
"received_at": "2026-04-05T08:31:12Z",
"channel": "sms"
}Webhook handler with keyword parsing
const express = require('express');
const app = express();
app.use(express.json());
// Normalise the reply to a known intent
function parseReply(body) {
const text = body.trim().toUpperCase();
const confirmKeywords = ['YES', 'Y', 'CONFIRM', 'OK', 'SI', 'JA'];
const cancelKeywords = ['NO', 'N', 'CANCEL', 'NEE'];
const reschedKeywords = ['RESCHEDULE', 'CHANGE', 'MOVE', 'VERPLAATS'];
if (confirmKeywords.includes(text)) return 'confirmed';
if (cancelKeywords.includes(text)) return 'cancelled';
if (reschedKeywords.includes(text)) return 'reschedule';
return 'unknown';
}
app.post('/webhooks/didfarm/inbound', async (req, res) => {
const { from, body, channel } = req.body;
// Look up the upcoming appointment for this phone number
const appointment = await db.appointments.findUpcoming(from);
if (!appointment) {
console.log(`No upcoming appointment for ${from}`);
return res.sendStatus(200);
}
const intent = parseReply(body);
switch (intent) {
case 'confirmed':
await db.appointments.update(appointment.id, {
status: 'confirmed',
});
await sendSms(from, 'Thank you! Your appointment is confirmed.');
break;
case 'cancelled':
await db.appointments.update(appointment.id, {
status: 'cancelled',
});
await sendSms(
from,
'Your appointment has been cancelled. '
+ 'To rebook, visit our website or call us.'
);
break;
case 'reschedule':
await db.appointments.update(appointment.id, {
status: 'reschedule_requested',
});
await sendSms(
from,
'We will contact you shortly to find a new time. '
+ 'You can also rebook online at our website.'
);
break;
default:
await sendSms(
from,
'Sorry, we did not understand your reply. '
+ 'Please reply YES to confirm or NO to cancel.'
);
}
res.sendStatus(200);
});200 status from your webhook handler, even if you cannot process the message. Returning an error causes DIDfarm to retry delivery, which could result in duplicate processing.
Cancellation Flow
Send a cancellation confirmation
When a patient cancels via reply, it is good practice to send an immediate confirmation so they know the cancellation was processed. You should also cancel any remaining scheduled reminders for that appointment.
async function handleCancellation(appointment) {
// 1. Update the appointment status
await db.appointments.update(appointment.id, {
status: 'cancelled',
cancelledAt: new Date(),
cancelledVia: 'sms_reply',
});
// 2. Remove any pending reminder jobs
await queue.removeByTag(`appointment:${appointment.id}`);
// 3. Send cancellation confirmation
await sendSms(
appointment.phone,
`Your appointment on ${appointment.dateFormatted} has been `
+ `cancelled. To rebook, visit ${process.env.BOOKING_URL} `
+ `or call us at ${process.env.OFFICE_PHONE}.`
);
// 4. Notify the provider / office
await notifyProvider(appointment.providerId, {
type: 'cancellation',
patient: appointment.patientName,
originalDate: appointment.datetime,
});
}WhatsApp Templates
WhatsApp requires pre-approved message templates for outbound notifications. Below are example templates you can submit for approval through the DIDfarm portal.
Reminder template with quick-reply buttons
Template name: appointment_reminder
Category: UTILITY
Language: en
Header: Appointment Reminder
Body: Your appointment with 1 is scheduled for 2
at 3, located at 4.
Please confirm or reschedule below.
Footer: Sent via DIDfarm
Buttons:
[Quick Reply] Confirm
[Quick Reply] RescheduleFollow-up template (no reply received)
Template name: appointment_followup
Category: UTILITY
Language: en
Body: Hi 1, we have not received your confirmation
for your appointment on 2 at 3.
Please reply to confirm or call us at 4.
Buttons:
[Quick Reply] Confirm
[Quick Reply] CancelHandling WhatsApp quick-reply button presses
When a recipient taps a quick-reply button, your webhook receives the button payload in the button_text field rather than in body:
{
"id": "msg_wa_9c4d3e2f",
"from": "+31612345678",
"to": "+31201234567",
"body": "",
"button_text": "Confirm",
"channel": "whatsapp",
"received_at": "2026-04-05T09:15:44Z"
}Best Practices
Timing
- Send two reminders — one 24 hours before and one 2 hours before the appointment. This gives recipients time to respond and still leaves a window for rebooking.
- Respect quiet hours — avoid sending reminders before 08:00 or after 21:00 in the recipient's local timezone. If a reminder falls outside this window, shift it to the nearest allowed time.
- Same-day bookings — for appointments booked less than 24 hours out, send a single reminder 2 hours before (or immediately after booking if less than 2 hours remain).
Message content
- Keep it short — SMS messages should be under 160 characters when possible to avoid multi-segment charges. Include only the essential details: provider name, date, time, and location.
- Include a clear CTA — always tell the recipient exactly how to respond. Use phrases like "Reply YES to confirm or NO to cancel."
- Add the location — include the address or clinic name so the patient can navigate directly from the message.
- Personalise — use the patient's first name and the provider's name for higher engagement.
- Offer a reschedule option — cancellations are better than no-shows. Make it easy to reschedule rather than just cancel.
Technical considerations
- Idempotency — tag each reminder with a unique reference (e.g.
appointment_id + label) and check for duplicates before sending to avoid double-sending on queue retries. - Delivery status tracking — configure the delivery status webhook to monitor whether messages were delivered, failed, or are still pending.
- Fallback strategy — if a WhatsApp message is undelivered after 60 seconds, automatically fall back to SMS.
- Rate limits — DIDfarm allows up to 30 messages per second per number. If you have a large batch of reminders firing at the same time, stagger sends over a few seconds or use multiple numbers.
FAQ
What if the patient does not reply?
If no reply is received after the second reminder, treat the appointment as unconfirmed. You can optionally send a final WhatsApp follow-up (using the appointment_followup template) 1 hour before. Some businesses also place an automated phone call as a last resort.
Can I send reminders to landline numbers?
SMS reminders cannot be delivered to landlines. If the recipient's number is a landline, you should fall back to email or voice call reminders. DIDfarm's number lookup API can help you detect number types before sending.
How do I handle timezone differences?
Store all appointment times in UTC internally. When composing the message, convert to the patient's local timezone using their country code or an explicit timezone preference stored in your system. Always display the timezone abbreviation (e.g. "10:30 AM CET") to avoid ambiguity.
What about GDPR compliance?
Appointment reminders are generally covered under "legitimate interest" or "performance of a contract" under GDPR, as they relate to a service the patient has already booked. However, you should still inform patients during booking that they will receive SMS/WhatsApp reminders and provide an opt-out mechanism. Consult your legal advisor for your specific use case.
Can I include a link in the reminder?
Yes. You can include a short URL to a confirmation page, a calendar add link, or a map link. Keep URLs short to conserve SMS character space. For WhatsApp, you can use call-to-action buttons with URLs for a better user experience.
How many reminders should I send?
Two reminders (24h and 2h) is the industry standard. Sending more than three reminders per appointment risks being perceived as spam and may lead to opt-outs. If you add a third, make it a different channel (e.g. email 7 days before, SMS 24h and 2h before).
Start sending appointment reminders
Enable SMS on your DIDfarm numbers and reduce no-shows today.