No-show rates for appointment-based businesses commonly run 15-30% without any reminder system. A simple, well-timed SMS reminder with an easy confirm path cuts that meaningfully - not because the message is clever, but because a lot of no-shows are just forgetting, and a text the day before fixes forgetting.
This is a complete, working version of that flow: schedule a reminder, send it, and handle the reply.
The shape of the flow
Three steps: schedule the reminder for the right time before the appointment, send it with a clear ask, and listen for the reply so a "C" to confirm or a "R" to reschedule actually does something instead of disappearing into an inbox nobody reads.
import { Dial } from "@getdial/sdk";
const dial = new Dial({ apiKey: process.env.DIAL_API_KEY });
async function scheduleReminder(appointment) {
const sendAt = new Date(appointment.time);
sendAt.setHours(sendAt.getHours() - 24); // 24 hours before
await dial.messages.schedule({
to: appointment.patientPhone,
from: appointment.clinicNumberId,
sendAt: sendAt.toISOString(),
body:
`Reminder: your appointment is tomorrow at ${appointment.timeLabel}. ` +
`Reply C to confirm or R to reschedule.`,
});
}That's the send side. The part that actually reduces no-shows is what happens next - the reply has to route somewhere real.
Handling the reply
A reminder without a reply handler is a one-way broadcast. The person who wants to reschedule has no path to do it except calling the front desk during business hours, which is exactly the friction that causes no-shows in the first place.
export async function handleInboundMessage(event) {
const body = event.body.trim().toUpperCase();
const appointment = await findAppointmentByPhone(event.from);
if (!appointment) return;
if (body === "C") {
await confirmAppointment(appointment.id);
await dial.messages.send({
to: event.from,
from: event.to,
body: "Confirmed! See you then.",
});
} else if (body === "R") {
await markForReschedule(appointment.id);
await dial.messages.send({
to: event.from,
from: event.to,
body: "No problem - our team will reach out to find a new time.",
});
}
}Wire this handler to your inbound message webhook and the loop closes: reminder goes out, reply comes back, the right thing happens on your side automatically.
Two upgrades worth making before shipping this for real
Add a second reminder closer to the appointment. A single reminder 24 hours out catches people who forgot about the appointment entirely. A second, shorter reminder 2-3 hours before catches people who remembered but got pulled into something else. Two touches meaningfully outperform one.
Fall back to voice for high-value appointments. For appointments where a no-show is expensive - a consult, a procedure slot that's hard to refill - consider an automated call instead of or in addition to SMS. A call that a patient answers and confirms verbally has a different commitment weight than a text they might not open.
await dial.calls.create({
to: appointment.patientPhone,
from: appointment.clinicNumberId,
agent: {
instructions:
"You are calling to confirm tomorrow's appointment. Confirm the time, " +
"ask if they need to reschedule, and end the call politely either way.",
},
});Why this is worth building instead of buying a point solution
Reminder tools exist as standalone products, but an agent-native reminder flow lives in the same system as everything else your agent does - the same number, the same customer record, the same conversation history. A reply to a reminder can trigger a reschedule flow that also updates your calendar system, notifies staff, and follows up automatically, because it's code you own, not a webhook into a third-party tool you're stitching together after the fact.
The whole flow above is under 40 lines. The return on those 40 lines, for a business where a no-show has real cost, is usually one of the highest-leverage things you can ship in an afternoon.