Guides
Step-by-step guide to building an AI agent that qualifies callers, checks live calendar availability, books appointments, and confirms — all during a single conversation.
Last updated
Every missed appointment slot costs revenue — in elective healthcare, home services, insurance, real estate, and education enrollment, the gap between a lead expressing interest and a booked consultation is where most conversion falls apart. Manual callbacks take hours. Web forms go stale. And the leads who would have booked end up calling a competitor who picked up first.
An AI appointment-setting agent eliminates that gap. It answers or calls leads within seconds, qualifies interest, checks your team's live availability, books the meeting, and confirms — all during a single conversation. No hold queues, no phone tag, no missed windows. This guide walks through how to build one in Thoughtly, step by step, using the platform's Agent Builder, mid-call Actions, and scheduling integrations.
By the end, you will have a working agent that qualifies inbound callers, checks calendar availability in real time, books the appointment, confirms it, and writes the outcome back to your CRMCRMThe system of record for leads, contacts, deals, and activity. Thoughtly reads from and writes to your CRM continuously. — all without a human touching the phone.
Before opening the Agent Builder, decide two things: what qualifies a lead for a booked appointment, and what your booking flow looks like.
In high-consideration consumer industries, qualification is about fit, not budget authority. Think about:
Write these down as concrete variables your agent will extract during the conversation.
Map the conversation path:
Open the Agent Builder and create a new agent. Give it a descriptive name like "Inbound Appointment Setter — Dental" or "HVAC Booking Agent."
The Start node speaks its text verbatim every time — no variation. Use it for your opening line plus any required compliance or consent language.
For example:
Hi, thanks for calling Greenfield Dental. This call may be recorded for quality purposes. How can I help you today?Keep the opener under three sentences. State who you are, handle consent if required by your industry, and hand the conversation to the caller.
In the agent's prompt (under Advanced Settings), describe the agent's role, personality, and scope. Be specific about the industry and the types of appointments you book.
You are a scheduling assistant for Greenfield Dental, a family dental practice in Austin, TX. Your job is to qualify callers, check appointment availability, and book consultations. You handle new patient intake, cleanings, and general consultations. You do not provide medical advice. If a caller asks about emergencies, direct them to call 911 or visit the nearest ER. Be warm, professional, and efficient.After the Start node, add Speak nodes that collect your qualification criteria. Each Speak node asks a question and extracts the answer into a VariableVariableA named value the voice agent stores during a conversation — caller name, intent, qualifying answers — and uses to drive routing and post-call actions..
Example qualification sequence for a home services company:
| Node | Question | Variable | Type |
|---|---|---|---|
| Node 1 | What type of service are you looking for? | service_type | Text |
| Node 2 | What's the ZIP code for the property? | zip_code | Text |
| Node 3 | How soon do you need this done? | urgency | Text |
| Node 4 | Are you the homeowner or a property manager? | caller_role | Text |
For each variable, write a clear extraction instruction. For example:
Extract the type of service the caller is requesting. Examples: HVAC repair, plumbing, electrical, general maintenance. If unclear, return empty.After collecting qualification data, use rule-based Outcomes to route the caller. Rule-based outcomes are deterministic — they evaluate variable values exactly, which is more reliable than prompt-based routing for critical decision points.
Example rules:
If zip_code is in your service area AND urgency is not empty → proceed to scheduling.
If zip_code is outside your service area → route to an "Out of Area" node that explains you cannot service that location.
If the caller does not qualify, do not just hang up. Offer to take their information for a callback, or transfer to a human who can help.
Go to Integrations in your Thoughtly workspace and connect your scheduling tool. Thoughtly supports Calendly, Cal.com, Acuity, Zoho Bookings, GoHighLevel, Mindbody, and Fence Flow.
Once connected, the scheduling actions become available in both the Agent Builder (for mid-call booking) and Automations (for pre-call or post-call workflows).
If you have multiple scheduling accounts — for example, separate Calendly event types for different providers or locations — you can select which account to use when you configure each action.
Scheduling actions accept an optional timezone. If not specified, Thoughtly uses this fallback order:
If your callers span multiple time zones (common in insurance, mortgage, and education enrollment), capture their timezone during the conversation and pass it to the scheduling action.
This is where the agent transitions from qualification to scheduling. Thoughtly supports two production patterns for mid-call booking.
This pattern — documented in the Thoughtly scheduling guide — checks availability live during the call. It handles any date the caller requests and works well for open-ended scheduling windows.
The flow uses four Speak nodes:
Create a Speak node (Prompt mode) that asks when the caller would like to come in. Add two Variables:
preferred_date (Text) — extraction instruction: "Extract the appointment date. Output YYYY-MM-DD. If unclear, return empty."
preferred_timezone (Text, optional) — capture if the caller mentions a timezone.
Add a Speak node with a brief hold message like "Let me check what times are open." Then add a mid-call Action: your scheduler's Get Available Times action. Map the date input to preferred_date and timezone to preferred_timezone.
Disable interruptions on this node so the caller does not break the integration flow.
Create a Speak node (Prompt mode) that presents the returned time slots. Use a prompt like:
timeslots: {{response}}
Your task is to provide a few (no more than 3) available time slots from the list, based on the person's request. If the timeslots is empty just say: "I don't have any openings for this day, should I check another one?"
Only provide and talk about information that is available in the timeslots list. If it is empty, do not come up with information; simply let the customer know that you don't have an opening for that date.Add a Variable selected_time to capture the caller's choice. Set up rule-based outcomes:
If selected_time is valid → proceed to booking.
If no slot chosen or the caller wants a different day → loop back to the availability-check node.
Add a Speak node with the message "One moment while I book that for you." Add your scheduler's booking action (Schedule Appointment or Create Booking). Map:
Date/time: selected_time
Timezone: preferred_timezone (or let it fall back to the agent default)
Attendee email: collected earlier, or collected in this node if not yet gathered.
Add rule-based outcomes on the same node:
booking_status == "confirmed" → route to confirmation node.
Else → route to an error-handling node that offers alternative times or transfers to a human.
If speed matters more than flexibility — such as a high-volume inbound queue where you want sub-30-second calls — you can pre-fetch available times in an Automation before the call starts.
The Automation runs a Get Available Times step, stores the result as metadata, and passes it into the agent call. The agent reads from metadata instead of making a live API call mid-conversation.
This works best for near-term booking windows (within a week). For far-future scheduling, Pattern A is more reliable.
After a successful booking, use a Speak node (Message mode, verbatim) to confirm:
You're all set for [date and time]. You'll receive a confirmation shortly. Is there anything else I can help you with?If you want the agent to read back dynamic details, use Prompt mode and reference the booking variables.
Add a Send SMS or Send Email action on the confirmation node to deliver a written confirmation with the appointment details. This gives the caller something tangible and reduces no-shows.
Set up an Automation with the On Call Completed trigger. This fires after every call and can:
Use the built-in test console in the Agent Builder to run through the full conversation flow. Check every path:
Use Sample Metadata in the test console to simulate contact attributes and CRM data that your agent might receive in production.
Once testing is solid, deploy the agent by assigning a phone number (Settings → Phone Numbers) and toggling it live. Start with a small volume of real calls to validate before scaling.
Track these metrics from Thoughtly's History and Analytics, your scheduling tool, and your CRM:
| Metric | What It Tells You | Target |
|---|---|---|
| Booking rate | Percentage of answered calls that result in a booked appointment | 30–50% for qualified inbound |
| Speed to book | Time from call start to confirmed appointment | Under 3 minutes |
| No-show rate | Percentage of booked appointments where the lead does not appear | Below 15% |
| Qualification accuracy | How often booked leads actually match your ideal criteria | Above 85% |
| Fallback transfer rate | Percentage of calls that needed a human handoff | Below 20% |
| Post-call CRM sync rate | Percentage of calls with complete CRM write-back | 100% |
Export call history from Thoughtly's History tab to analyze trends over time. Look for patterns: if no-show rates climb, your confirmation step or SMS follow-up may need work. If booking rates are low, review your qualification criteria — you may be filtering too aggressively.
Thoughtly integrates with Calendly, Cal.com, Acuity, Acuity Enterprise, Zoho Bookings, GoHighLevel, Mindbody, and Fence Flow. All follow the same pattern: check availability, present slots, book, and confirm. You can connect multiple accounts and select which one to use per action.
Yes. Supported schedulers expose reschedule and cancel actions. You can build a branch early in the conversation — "Are you calling to book a new appointment or change an existing one?" — and route to the appropriate flow. The reschedule path typically looks up the existing booking, presents new slots, and moves the appointment.
Build a fallback outcome for persistent action failures. The agent can say something like "I'm having trouble checking the schedule right now. Let me take your information and someone will call you back within the hour." Capture the caller's details and trigger a post-call Automation to alert your team.
Not necessarily. The same agent logic works for both — the main difference is the opening. For inbound, the caller initiates and you respond. For outbound (e.g., following up on a form fill or re-engaging a dormant lead), the agent initiates and introduces the reason for calling. The qualification and booking flow can be identical.
Use Variables to capture the appointment type or location early in the conversation, then use rule-based Outcomes to route to the correct scheduling action. Each action can point to a different event type or calendar. This is better than building separate agents for each service line.