Communications

WhatsApp Bot

← Back to Communications

The WhatsApp bot is the platform's primary inbound/outbound channel. Guests message your tenant's WA number; the bot persists the message, runs language + mood analysis, and surfaces it to you. Outbound — task notifications, check-in instructions, pre-checkout reminders — flows out through the same number.

Tenant configuration

Each tenant has its own WhatsApp Cloud API setup:

  • whatsappPhoneNumberId — Meta-assigned phone-number ID; the routing key.
  • whatsappBusinessAccountId — Meta WABA the number belongs to.
  • whatsappVerifyToken — per-tenant verify token for the webhook handshake.
  • whatsappAccessToken (secret) — the access token the platform uses to call the Cloud API.

Configure under Settings → Integrations.

⚠ If whatsappPhoneNumberId is NULL on the tenant row, every inbound webhook is silently rejected. That was the #218 bug. Fix shipped May 2026; admins should verify the value is populated after onboarding.

Inbound webhook

Meta delivers inbound messages to:

POST https://flatsbratislava.com/api/webhooks/wa/t/<tenant-slug>

The URL is tenant-scoped — the <tenant-slug> in the path is the routing key. This is the canonical multi-tenant webhook pattern (see project_webhook_multitenant_pattern in memory). The HMAC signature on the request is verified against the tenant's whatsappAccessToken — see #71.

On a verified inbound:

  1. Message persisted to messages table.
  2. LLM language detection writes to reservation.guest.language if higher confidence than current.
  3. LLM mood + comm-type analysis writes to reservation.guestMood, reservation.guestCommunicationType.
  4. Task seeder re-evaluates any auto-resolve conditions that depend on these fields.
  5. The message shows up in: - The reservation's thread tab - The /v28/wa-comm operator view - The Pulse "recent messages" card (if the AI couldn't confidently reply)

Outbound messages

Free-text (inside 24h window)

A teammate's reply, an AI suggestion accepted, or a task action that sends a custom message — all use the free-text path when the recipient messaged us in the last 24h.

Template (outside 24h window OR for compliance-sensitive sends)

Pre-approved Meta templates with {{1}} style placeholders. The platform substitutes values at send time. Examples:

  • checkin_instructions — Send Check-in fallback.
  • task_notification_v2 — outbound task notification with up-to-3 buttons.
  • task_resolved — fallback for closed-window operator notifications.

Interactive buttons

Templates can carry up to 3 button replies. When the recipient taps a button, the response comes in as a regular inbound message tagged with the button payload. The platform routes it back to the right task — see handleButtonResponse in whatsappService.ts.

Silent delivery failure (closed window)

A free-text send into a closed window can return HTTP 200 from Meta and silently fail to deliver. The platform now always falls back to a template path when free-text is rejected; the fix landed alongside the cleaning-walkthrough rollout.

If a guest insists they got no message, check:

  1. Admin → Activity Log — was the send recorded?
  2. Admin → Webhook Logs — did Meta return 200 + a messages[] array?

Inbound from teammates

Cleaners and hosts message the same number with status updates and photos. The platform identifies them by phone number → teammate row → routing.

The cleaner-WA walkthrough flow is its own multi-step conversation — see Team & Access → Cleaner Walkthrough.


  • #218 — WA bot dead (whatsappPhoneNumberId NULL bootstrap).
  • #181 — admin-photo flood + admin-chat visibility on /v28/wa-comm.
  • #71 — webhook signature verification (Hospitable, WhatsApp, Beds24).
  • #80 — webhook payload trust boundary (tenant-spoofing fallback removed).
  • #212 — cleaner WA free-text + photo reports → LLM intent classification.
Source: the FlatsBratislava operator manual.