Communications
How the platform talks to guests, cleaners, hosts, and you. Everything in this section is a layer on top of the WhatsApp Cloud API.
In this section
- WhatsApp Bot — the inbound bot, routing rules, the 24h window
- AI Suggest — AI-drafted replies on guest messages
- Languages — how the system decides what language to write in
- FAQ Knowledge Base — the AI's source of operator-curated answers
The three communication channels
| Channel | Direction | Used for |
|---|---|---|
| WhatsApp Cloud API | inbound + outbound | Primary. Guests, teammates, operator notifications |
| In-app messaging | internal | Notes between teammates, AI drafts before sending |
| Email (SMTP) | outbound | Invoices, owner statements (per-tenant SMTP; see Settings) |
Webhooks from booking channels (Hospitable, Beds24) are not communications — they're inbound data updates that may trigger communications.
The 24-hour WhatsApp window
Meta's policy: you can only send free-text WhatsApp messages to a phone number that messaged your business in the last 24 hours. Outside that window, you must use a pre-approved template.
The platform handles this automatically:
- If the window is open → free-text or interactive template, whichever is appropriate.
- If the window is closed → fall back to an approved template (
task_resolved,task_notification_v2,checkin_instructions, …).
If neither is possible (no opted-in number, no template approved for the use case, Meta error), the platform logs to app_errors. The fix for the silent-delivery-failure pattern was added in #218-era work — when Meta returns HTTP 200 for a closed-window send but the message never delivers, we now retry through the template path instead of marking the task done.
Inbound message flow
Guest sends WA message
▼
WhatsApp Cloud API webhook fires → POST /api/webhooks/wa/t/<slug>
▼
Verify HMAC signature for this tenant (per #218 / #71)
▼
Persist message to messages table
▼
LLM language detection → reservation.guest.language updated
▼
LLM mood + communication-type analysis → reservation.guestMood updated
▼
Task seeder re-evaluates rules that depend on guestMood (e.g. Rule 21 thank-you)
▼
AI Suggest drafts a reply (if enabled for this template)
▼
Surfaces on Pulse + WA Comm screens for operator
If you ever see "WA bot dead, every inbound webhook silently rejected" — that was #218. Root cause: tenants.whatsappPhoneNumberId was NULL on the tenant row, so the webhook receiver couldn't identify which tenant to route inbound to → rejected. Fix: bootstrap migration populated the field for every tenant; admins can edit it under Settings → Integrations.
Related issues
- #218 — WA bot dead (tenant phone-number-ID bootstrap).
- #181 — admin-photo flood & admin-chat visibility.
- #182 — cleaner WA walkthrough mixed-language fix.
- #156 — AI Suggest language no longer polluted by synthetic system notes.
- #71 — webhook signature verification.
- #80 — webhook payload trust boundary.