Appointment Booking Agent

Build a voice agent for scheduling, rescheduling, and confirming appointments.

Appointment Booking Agent

A voice agent that handles appointment scheduling, rescheduling, and confirmations for healthcare, salons, or service businesses.

Configuration

{
  "agent": {
    "name": "Appointment Assistant",
    "language": "en-US",

    "llmProvider": "gemini-2.5",
    "llmModel": "gemini-2.5-flash-lite",
    "llmTemperature": 0.5,

    "sttProvider": "deepgram",
    "sttModel": "nova-3",

    "ttsProvider": "azure",
    "ttsVoice": "en-US-JennyNeural",

    "greetingMessage": "Hello! This is Dr. Smith's office. I can help you schedule, reschedule, or confirm an appointment. What would you like to do?",

    "prompt": "..."
  }
}

System Prompt

You are an appointment scheduling assistant for Dr. Smith's Medical Clinic.

## Your Capabilities
- Schedule new appointments
- Reschedule existing appointments
- Confirm upcoming appointments
- Cancel appointments
- Answer questions about office hours and location

## Office Information
- Hours: Monday-Friday 8 AM to 5 PM, Saturday 9 AM to 1 PM
- Address: 456 Health Center Drive, Suite 200
- Phone: 555-123-4567

## Appointment Types
- General checkup: 30 minutes
- Follow-up: 15 minutes
- New patient consultation: 45 minutes
- Physical exam: 60 minutes

## Guidelines

### Scheduling Flow
1. Ask what type of appointment they need
2. Check availability using the tool
3. Offer 2-3 available time slots
4. Confirm their selection
5. Get/verify patient name and phone number
6. Confirm all details before ending

### Date/Time Handling
- Always confirm dates: "That's Tuesday, January 15th at 2:30 PM, correct?"
- Speak times clearly: "two thirty in the afternoon"
- Offer morning, afternoon, or specific times based on preference

### Required Information for Booking
- Patient full name
- Phone number
- Type of appointment
- Preferred date/time
- Insurance (for new patients)

### Rescheduling
1. Look up existing appointment
2. Confirm what appointment they want to change
3. Get new preferred time
4. Offer available slots
5. Confirm the change

### Cancellation Policy
Mention: "Please note, we ask for 24 hours notice for cancellations to avoid a fee."

## Example Conversations

**New Appointment:**
Patient: "I need to schedule a checkup"
You: "I can help with that. Do you have a preference for morning or afternoon?"
Patient: "Afternoon works better"
You: "How about Tuesday the 15th at 2:30 PM, or Wednesday the 16th at 3 PM?"
Patient: "Tuesday works"
You: "Great! I have you down for Tuesday, January 15th at 2:30 PM. May I have your name?"
Patient: "John Smith"
You: "And what's the best phone number to reach you, Mr. Smith?"
Patient: "555-867-5309"
You: "Perfect. You're all set for a checkup with Dr. Smith on Tuesday, January 15th at 2:30 PM. We'll send a text reminder the day before. Is there anything else?"

**Confirmation Call:**
You: "Hi, I'm calling from Dr. Smith's office to confirm your appointment tomorrow at 10 AM. Can you confirm you'll be there?"
Patient: "Yes, I'll be there"
You: "Wonderful! As a reminder, please arrive 10 minutes early and bring your insurance card. See you tomorrow!"

Tools

Check Availability

{
  "type": "function",
  "function": {
    "name": "check_availability",
    "description": "Check available appointment slots",
    "parameters": {
      "type": "object",
      "properties": {
        "date": {
          "type": "string",
          "description": "Preferred date (YYYY-MM-DD)"
        },
        "appointment_type": {
          "type": "string",
          "enum": ["checkup", "followup", "new_patient", "physical"],
          "description": "Type of appointment"
        },
        "time_preference": {
          "type": "string",
          "enum": ["morning", "afternoon", "any"],
          "description": "Time preference"
        }
      },
      "required": ["appointment_type"]
    }
  }
}

Book Appointment

{
  "type": "function",
  "function": {
    "name": "book_appointment",
    "description": "Book a new appointment",
    "parameters": {
      "type": "object",
      "properties": {
        "patient_name": {
          "type": "string",
          "description": "Patient's full name"
        },
        "phone": {
          "type": "string",
          "description": "Contact phone number"
        },
        "appointment_type": {
          "type": "string",
          "description": "Type of appointment"
        },
        "datetime": {
          "type": "string",
          "description": "Appointment date and time (ISO 8601)"
        }
      },
      "required": ["patient_name", "phone", "appointment_type", "datetime"]
    }
  }
}

Reschedule Appointment

{
  "type": "function",
  "function": {
    "name": "reschedule_appointment",
    "description": "Reschedule an existing appointment",
    "parameters": {
      "type": "object",
      "properties": {
        "appointment_id": {
          "type": "string"
        },
        "new_datetime": {
          "type": "string",
          "description": "New date and time"
        }
      },
      "required": ["appointment_id", "new_datetime"]
    }
  }
}

Lookup Appointment

{
  "type": "function",
  "function": {
    "name": "lookup_appointment",
    "description": "Look up an existing appointment by phone number",
    "parameters": {
      "type": "object",
      "properties": {
        "phone": {
          "type": "string"
        }
      },
      "required": ["phone"]
    }
  }
}

Tool Handlers

func handleCheckAvailability(params map[string]any) (string, error) {
    appointmentType := params["appointment_type"].(string)
    timePreference := params["time_preference"].(string)

    duration := getAppointmentDuration(appointmentType)
    slots, _ := calendar.GetAvailableSlots(duration, timePreference, 3)

    if len(slots) == 0 {
        return "I don't see any availability for that time preference. Would you like to try a different day or time?", nil
    }

    response := "I have the following times available: "
    for i, slot := range slots {
        response += formatSlotForSpeech(slot)
        if i < len(slots)-1 {
            response += ", or "
        }
    }
    response += ". Which works best for you?"

    return response, nil
}

func formatSlotForSpeech(slot time.Time) string {
    // "Tuesday, January 15th at 2:30 in the afternoon"
    return slot.Format("Monday, January 2nd") + " at " +
           formatTimeForSpeech(slot)
}

func formatTimeForSpeech(t time.Time) string {
    hour := t.Hour()
    minute := t.Minute()
    period := "in the morning"
    if hour >= 12 {
        period = "in the afternoon"
        if hour > 12 {
            hour -= 12
        }
    }

    if minute == 0 {
        return fmt.Sprintf("%d o'clock %s", hour, period)
    }
    return fmt.Sprintf("%d %02d %s", hour, minute, period)
}

Outbound Confirmation Calls

func sendConfirmationCalls() {
    tomorrow := time.Now().Add(24 * time.Hour)
    appointments, _ := db.GetAppointmentsForDate(tomorrow)

    for _, apt := range appointments {
        initiateConfirmationCall(apt)
    }
}

func initiateConfirmationCall(apt Appointment) {
    client.Calls.Create(CallRequest{
        AgentID: "appointment_confirmation",
        To:      apt.PatientPhone,
        Variables: map[string]string{
            "patientName":       apt.PatientName,
            "appointmentTime":   apt.DateTime.Format("3:04 PM"),
            "appointmentDate":   apt.DateTime.Format("January 2"),
            "doctorName":        apt.DoctorName,
            "appointmentType":   apt.Type,
        },
    })
}

Confirmation Agent Prompt:

You are calling to confirm an appointment.

Greeting: "Hi, this is {{doctorName}}'s office calling for {{patientName}}. We're confirming your {{appointmentType}} appointment tomorrow, {{appointmentDate}} at {{appointmentTime}}."

If confirmed: "Wonderful! Please arrive 10 minutes early. See you tomorrow!"

If needs to reschedule: Use the reschedule tool.

If no answer: Mark for callback.

SMS Integration

func sendAppointmentConfirmation(apt Appointment) {
    message := fmt.Sprintf(
        "Your appointment with %s is confirmed for %s at %s. " +
        "Reply CONFIRM to confirm or RESCHEDULE to change. " +
        "Location: %s",
        apt.DoctorName,
        apt.DateTime.Format("Mon, Jan 2"),
        apt.DateTime.Format("3:04 PM"),
        apt.Location,
    )

    smsClient.Send(apt.PatientPhone, message)
}

Analytics

type BookingMetrics struct {
    TotalCalls           int
    SuccessfulBookings   int
    Reschedules          int
    Cancellations        int
    NoShows              int
    AverageCallDuration  time.Duration
    BookingConversionRate float64
}

func trackBookingCall(call *Call, outcome string) {
    metrics.Increment("appointments.calls.total")
    metrics.Histogram("appointments.call_duration", call.Duration.Seconds())

    switch outcome {
    case "booked":
        metrics.Increment("appointments.bookings.success")
    case "rescheduled":
        metrics.Increment("appointments.reschedules")
    case "cancelled":
        metrics.Increment("appointments.cancellations")
    }
}

Next Steps