Skip to main content
This guide shows production pattern for scheduling inside a v1.8 agent using mid-call Actions.

Before you start

1) Connect your scheduling tool

Go to Integrations and connect your scheduler so it is available in both:
Integrations screen with Calendly and Cal.com connected

Key building blocks (how v1.8 scheduling works)

Variables (capture the caller’s date/time)

Variables extract immediately after the caller’s latest reply and before outcome evaluation, so your routing can validate the date/time right away. If you loop back to the same node, variables re-extract and overwrite prior values (perfect for “try again” date collection). See Loops.
Variables panel with a "preferred_datetime" variable configured

Actions (run scheduling mid-call)

In v1.8, Actions run mid-call from a Speak node. When Actions exist, the node can auto-proceed without waiting for another caller reply, and rule-based outcomes are recommended because outcomes fire based on internal values/results.
Speak node Actions panel with a scheduling action selected

Calendly timezone handling (important)

Calendly Actions accept an optional timezone. If not set, Thoughtly falls back to:
  1. timezone input (action config) -> 2) agent timezone (advanced settings) -> 3) America/New_York.
See Calendly timezone handling for details.

Flow overview

  1. Ask for preferred date/time (Speak -> Prompt)
  2. Extract preferred_datetime (Variable)
  3. Validate (Outcomes -> loop if invalid)
  4. Book (Speak node with Scheduling Action)
  5. Confirm (Message / Prompt)
  6. Fallback (offer alternatives or Transfer)

Step-by-step (Agent Builder)

Step 1 - “Collect date/time” Speak node

Create a Speak node that asks something like:
  • “What day and time works best for you?”
  • “If you have a timezone preference, tell me as well.”
Create Variables on this node:
  • preferred_datetime (Text)
  • preferred_timezone (Text, optional)
Extraction instruction suggestion (copy/paste style):
Goal: extract the appointment date and time the caller states.
Output: ISO-like text (for example: 2024-01-08T10:30:00Z).
If absent or unclear: return empty.
Do not invent values.

Step 2 - Validate and loop (Outcomes)

Add prompt-based Outcomes from the same Speak node:
  • If the caller did not provide a time -> self-loop back to this node (“Sorry - what date and time?”)
  • Else -> continue to booking
Outcomes rules showing self-loop and success path

Step 3 - Booking Speak node (Actions)

Create a new Speak node:
  • Message: “One moment while I book that for you.”
  • Add an Action for your scheduler (Calendly or Cal.com) and map:
    • Date/time input: preferred_datetime
    • Timezone: preferred_timezone (or rely on the Calendly fallback order)
Authoring tip: disable interruptions for mid-call Actions so the caller does not interrupt during booking.
Calendly "Schedule appointment" action mapping fields

Step 4 - Confirm vs error (rule-based Outcomes after booking)

In the same booking node, add rule-based outcomes that check Action outputs such as:
  • booking_status == "confirmed" -> confirmation node
  • Else -> error-handling node (try different time / get availability / transfer)

Step 5 - Confirmation Speak node

Use Message mode if you want an exact script:
  • “You’re all set for [date/time]. You’ll receive a confirmation shortly.”
Confirmation node with verbatim message enabled

Tips and tricks (prompting + reliability)

Use a strict date-only extractor for validation loops

This keeps your validation clean when the caller is vague or revises their date.
Print ONLY one line with the ISO date (YYYY-MM-DD). No labels, no prose, no JSON.
You are given ONLY the latest caller message and TODAY’S DATE (CURRENT_DATE) in the America/New_York timezone. Extract exactly one date the caller intends for scheduling and output ONLY that date in YYYY-MM-DD. No other text.

Rules
1) Prefer the most specific date mentioned. If multiple are given, choose the earliest that matches the caller’s intent modifiers (e.g., “late”, “end of”).
2) If the mentioned date would be in the past relative to CURRENT_DATE, roll it forward to the next logical occurrence (e.g., same month/day next year, or the next instance of that weekday).
3) If the caller is vague (e.g., “some time next week”, “next month”, “this week”, “what do you have available”), ALWAYS produce a date by applying the mapping below.
4) Assume ISO weeks start Monday; “weekend” = Saturday–Sunday. If a fallback lands on a weekend and no weekend was requested, use the next business day (Mon–Fri).
5) Output must be a valid calendar date within the next 365 days. If your first choice falls outside, choose the nearest valid alternative that respects the intent.

Relative-Date Mapping (examples; always relative to CURRENT_DATE)
- “today” → CURRENT_DATE
- “tomorrow” → CURRENT_DATE + 1 day
- “day after tomorrow” → CURRENT_DATE + 2 days
- Bare weekday (“Friday”) → next occurrence of that weekday after CURRENT_DATE
- “this <weekday>” → that weekday in the current week; if already passed, use the same weekday next week
- “this week” / “sometime this week” → the soonest remaining day this week after CURRENT_DATE
- “next week” / “sometime next week” → Monday of next week
- “weekend” / “this weekend” → upcoming Saturday
- “next weekend” → Saturday of next week
- “this month” → the earliest remaining day this month after CURRENT_DATE
- “next month” / “sometime next month” → the 1st business day of next month
- “early <month>” → 5th of that month; “mid <month>” → 15th; “late <month>” → 25th
- “end of <month>” → last calendar day of that month
- “in N days/weeks/months” → add N with standard calendar arithmetic (weeks = 7 days; months add by month, clamping to month end if needed)
- “a couple of weeks” → 14 days
- Ordinal day without month (“the 15th”) → the next 15th on the calendar (this month if still upcoming, else next month)
- Month/day without year → this year if still upcoming; otherwise next year
- No date intent / open-ended (“what do you have available”, “ASAP”, “whenever”) → next business day after CURRENT_DATE

Use a full datetime extractor right before booking

This captures the final intent, including confirmation of a proposed slot.
The final scheduled datetime the caller intends, returned as YYYY-MM-DDTHH:MM:SS (24h).
From FULL_CONVERSATION, extract exactly one datetime the caller intends for scheduling. Output ONLY one string in the format YYYY-MM-DDTHH:MM:SS and nothing else.


Conversation logic
1) Consider only the caller’s latest clear intent. If the caller revises the time/date later, the latest revision wins.
2) If the agent proposes a slot and the caller affirms (e.g., “yes”, “works”, “sounds good”), use that proposed slot.
3) Ignore tentative or rejected options that are later superseded.

Date resolution (vague → concrete)
- “today” → CURRENT_DATE
- “tomorrow” → +1 day
- Bare weekday (“Friday”) → next occurrence after CURRENT_DATE
- “this <weekday>” → that weekday in the current ISO week (Mon–Sun); if already past, use next week
- “this week” / “sometime this week” → soonest remaining business day this week after CURRENT_DATE
- “next week” → Monday next week
- “weekend” / “this weekend” → upcoming Saturday
- “next weekend” → Saturday next week
- “this month” → earliest remaining day this month
- “next month” → 1st business day of next month
- Ordinal day without month (“the 15th”) → next 15th (this month if upcoming, else next month)
- Month/day without year → this year if upcoming, else next year
- “in N days/weeks/months” → add N with calendar arithmetic (weeks=7 days; months clamp to month end)
- “early/mid/late <month>” → 05/15/25 of that month
- If fallback date lands on weekend and caller didn’t ask for weekend, use next Monday.

Time resolution (vague → concrete, 24h)
- Exact times → parse as given (handle “am/pm”).
- “noon”/“midday” → 12:00:00
- “midnight” → 00:00:00 (on the chosen date)
- “morning” → 10:00:00
- “early morning” → 08:00:00
- “afternoon” → 15:00:00
- “evening” → 18:00:00
- “late evening” / “tonight” → 20:00:00
- “EOD” / “end of day” → 17:00:00
- “lunchtime” → 13:00:00
- “quarter past X” → X:15:00; “half past X” → X:30:00; “quarter to X” → (X-1):45:00
- If no time is given, default to 10:00:00 (business-friendly).
- If the chosen time falls outside business days and caller did not indicate off-hours/weekend, keep the date but set time to 10:00:00 next business day.

Edge cases
- If caller is completely open-ended (“what do you have available”, “whenever”), choose next business day at 10:00:00.

Output
Return exactly one line in this format: YYYY-MM-DDTHH:MM:SS
No labels, no prose, no JSON, no quotes.

Offer only real availability

Use this prompt when you’re reading from an availability response to avoid hallucinated slots.
timeslots: {{response}} 

Your taks 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 then do not come up with information, simply let customer know that you don't have an opening for a date.

See also

  • Actions - mid-call integrations and execution order
  • Variables - extraction and overwrite behavior
  • Outcomes - rule-based vs prompt-based routing
  • Automations - prefetch and data passing
  • Calendly - action details and timezone handling
  • Cal.com - action details