All posts
Build an Agent That Sends Appointment Reminders (With Working Code)
TutorialBy Dial Engineering·7 min read·Aug 5, 2026·0

Build an Agent That Sends Appointment Reminders (With Working Code)

No-shows cost service businesses real money, and the fix is a well-timed reminder with an easy way to confirm or reschedule. Here is a working reminder flow in under 40 lines - schedule, send, and handle the reply.


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.

Did you enjoy this post?

0 claps