Journey 2: Inquiry → Booking

How a conversation turns into a Cal.com appointment

Interest expressed Karen identifies intent Shares booking link Cal.com booking Webhook fires Confirmation Pre-care handoff
STEP 1Conversation

Lead expresses interest in a procedure

During any conversation — WhatsApp, Instagram, or website widget — a lead signals booking intent. "I want to try Botox," "Can I book a consultation?" Karen's AI pipeline classifies this as booking-related and surfaces the appropriate booking actions.

▶ Intent classification via prompt-builder + model
Source files
src/prompt-builder.jsselectActionsForContext()
src/model.js → intent classification in model response
What happens
The prompt builder calls selectActionsForContext(), which includes [ACTION:suggest_booking] and [ACTION:check_availability] in the available actions list when conversation context is booking-related. The model parses these action tags and triggers the booking flow.
DB tables
conversations, contacts
STEP 2Karen AI → Patient

Karen shares the booking link

Karen responds with Oshun's Cal.com booking page — cosmetic.oshunja.com/booking. She explains what to expect at the consultation, mentions it's free, and reinforces procedure benefits to reduce drop-off before the click.

▶ Booking link delivery via calendar action
Source files
src/actions/calendar.js — booking action handlers
What happens
The booking URL is pulled from tenant config and inserted into Karen's response. Karen crafts a message that contextualises the booking — procedure name, what happens at a consultation, confirmation that it's free — then delivers it on whichever channel the lead is using.
Env vars
CALCOM_API_KEY, CALCOM_WEBHOOK_SECRET
STEP 3Cal.com

Patient books via Cal.com

The patient clicks the link, picks a date and time, and fills in their name and phone number. Cal.com creates the booking, sends a confirmation email directly to the patient, and fires a webhook back to the system.

▶ Cal.com webhook ingestion + contact match
Source files
src/webhooks/chatwoot.jsapp.post('/webhooks/calcom') (line 329)
What happens
The webhook handler extracts patient name, email, phone, procedure type, and date/time from the Cal.com payload. It then attempts to match against an existing contact by phone or email. If no match is found, a new contact record is created. Booking details are written to the bookings table.
DB tables
bookings, contacts
STEP 4Karen AI → Patient

Karen sends booking confirmation

Karen sends a confirmation on whichever channel the patient came in on: "Your consultation for Botox is confirmed for Thursday at 2 PM. Here's what to know before your visit…" Pre-care basics are included so the patient feels prepared from the moment they book.

▶ Confirmation + reminder scheduling
Source files
src/actions/calendar.js — confirmation handler
What happens
After the Cal.com webhook is processed, the confirmation handler fires a personalised message on the patient's original channel (WhatsApp, Instagram DM, or widget). Simultaneously, pre-appointment reminder jobs are written to booking_reminders — these will fire at configured intervals leading up to the appointment date.
DB tables
booking_reminders
STEP 5Database

Contact record updated

The contact record is updated with the appointment details — procedure type, date, time, and booking source (WhatsApp, IG, direct). This attribution feeds analytics that track which channels convert to bookings most effectively.

▶ Contact update + channel attribution
Source files
src/contacts.jsupdateContactIdentifiers() (line 145)
src/actions/attribution/resolve.js
What happens
updateContactIdentifiers() merges any new identifiers (phone, email) discovered at booking time into the unified contact record. The attribution resolver logs the booking source channel to attribution_events, enabling reporting on which channel (WhatsApp, IG, widget) drove each conversion.
DB tables
contacts, attribution_events, booking_reminders
STEP 6→ Journey 3

Hands off to pre-appointment flow

The booking triggers the pre-appointment journey. Three days before the appointment, the automated care plan system activates — sending pre-care guides, intake forms, and reminders. That story continues in Journey 3.

▶ Care plan activation on booking
Source files
src/actions/care/plans.jsstartCarePlan() (line 181)
What happens
startCarePlan() is called with the procedure type from the booking payload. Each procedure (Botox, filler, laser, etc.) has its own pre-care template containing timing rules, guide content, and intake form links. The care plan engine schedules all pre-appointment touchpoints automatically from this point forward.
DB tables
care_plans, care_plan_steps