# n8n Appointment Booking Workflow This example shows how to use OpenWA and n8n to collect appointment requests over WhatsApp, check availability in an external system, and send a confirmation or alternative time slots. The workflow is intentionally generic. The availability source can be Google Calendar, Cal.com, a CRM, a database, or any HTTP API that returns available slots. ## Flow ``` [OpenWA Trigger] │ └── Events: message.received │ ▼ [IF: booking intent?] │ ├── false → [OpenWA: Send Text] │ "Thanks for your message. A team member will reply soon." │ └── true │ ▼ [Set: normalize request] │ ▼ [Availability Source] │ ├── available → [Create Booking] → [OpenWA: Send Text confirmation] │ └── unavailable → [OpenWA: Send Text with alternative slots] ``` ## Trigger Use the **OpenWA Trigger** node. | Field | Value | | ----- | ----- | | Event | `message.received` | | Session | Your connected OpenWA session | The incoming message body is available at: ```text {{$json.data.body}} ``` The sender chat ID is available at: ```text {{$json.data.chatId}} ``` ## Booking Intent Check Add an **IF** node after the trigger. For a simple first version, check whether the incoming message contains booking-related words such as appointment, booking, schedule, reserve, cita, or reserva. For a production workflow, replace this with a classifier, a structured form flow, or your CRM-specific routing rules. ## Normalize the Request Add a **Set** node to extract the values your booking system expects. Suggested fields: | Field | Example value | | ----- | ------------- | | `chatId` | `{{$json.data.chatId}}` | | `phone` | `{{$json.data.from}}` | | `message` | `{{$json.data.body}}` | | `requestedDate` | Parsed date from the message or a default fallback | | `service` | Parsed service name or workflow default | If the message does not contain enough information, send a clarification question instead of creating a booking. Example clarification message: ```text Thanks. What day and time would you prefer for the appointment? ``` ## Availability Check Use whichever node matches your scheduling source: | Source | n8n node | | ------ | -------- | | Google Calendar | Google Calendar or HTTP Request | | Cal.com | HTTP Request | | Internal API | HTTP Request | | Database | PostgreSQL / MySQL / SQLite node | | Spreadsheet | Google Sheets | The availability step should return whether the requested slot is available and, if not, a small list of alternatives. ## Confirmation Message When the requested slot is available, create the booking in your scheduling source and send a confirmation with the **OpenWA: Send Text** node. | Field | Value | | ----- | ----- | | Resource | Message | | Operation | Send Text | | Chat ID | `{{$json.chatId}}` | | Text | Confirmation message | Example confirmation text: ```text Your appointment is confirmed for {{$json.slot}}. Reply CANCEL if you need to cancel or change it. ``` ## Alternative Slots Message When the requested slot is not available, send available alternatives instead of failing silently. Example text: ```text That time is not available. These slots are open: 1. {{$json.alternatives[0]}} 2. {{$json.alternatives[1]}} Reply with 1 or 2 to confirm one of these options. ``` ## Operational Notes - Store booking state outside WhatsApp, for example in your scheduling system, CRM, or database. - Add an idempotency key based on the incoming `id` (the message ID in the `message.received` payload) to avoid duplicate bookings if a workflow is retried. - Confirm the booking only after the external system accepts the slot. - Add a fallback path for unsupported messages or missing required fields. - Respect applicable messaging rules and avoid unsolicited or high-volume messages. ## Minimal Node Checklist - OpenWA Trigger: receives `message.received` events. - IF: detects booking intent. - Set: normalizes `chatId`, message body, requested date/time, and service. - Availability node: checks the calendar, API, database, or spreadsheet. - Booking node: creates the appointment only when a slot is available. - OpenWA Send Text: sends confirmation, alternatives, or clarification.