Skip to main content

Web Chat

Web chat is a public, web-based way to run conversation flows. The same flow that powers your WhatsApp inbound handler can also be triggered from a plain HTTP endpoint and rendered as a web chat experience. Useful for desktop visitors, contacts without WhatsApp installed, or as a fallback when WhatsApp is degraded.

When to use it

  • You want a chat experience on your campaign landing for visitors on desktop.
  • You want a fallback link members can click when your WhatsApp account is restricted (see Meta health).
  • You're testing a flow before pushing it to WhatsApp and want a one-click way to walk through it.

How it works

The web-chat API is anonymous, rate-limited, and exposes three endpoints under /api/public/chat:

POST /api/public/chat/start
POST /api/public/chat/send
GET /api/public/chat/status?sessionId={id}

Starting a session

POST /api/public/chat/start
{
"tenantSlug": "acme", // optional — see "tenant resolution" below
"flowSlug": "welcome", // matches trigger keywords or flow name
"phone": "+34666...", // optional
"memberCode": "ABC123" // optional
}

The server resolves the tenant (see below), finds the active flow whose trigger keywords or name match flowSlug, and starts a session. It returns:

{
"sessionId": "...",
"messages": [
{ "type": "text", "body": "Welcome!" },
{ "type": "buttons", "body": "Pick one:", "buttons": [...] }
]
}

The shape of messages mirrors what WhatsApp sends — text, buttons, list, image, video, document, audio, CTA URL.

Sending a reply

POST /api/public/chat/send
{ "sessionId": "...", "message": "Yes", "buttonReplyId": "btn_yes" }

The flow advances; the response contains the new messages. Continue until the flow ends or hits a close_conversation action.

Tenant resolution

The server resolves which tenant the chat belongs to in this order:

  1. Explicit tenantSlug in the request body.
  2. Custom domain — if Request.Host matches a tenant's WhiteLabelConfig.CustomDomain, that tenant is selected.
  3. Abp-TenantId header (used by admin previews).

Then it looks up the flow by trigger keywords (case-insensitive CSV match) and falls back to the flow's name. Tenant resolution happens before the flow lookup, so two tenants using the same trigger keyword won't collide.

Step-by-step

Make a flow available on web chat

  1. Open the flow in Communications → Flows.
  2. Make sure it's Active.
  3. Set Trigger keywords — a comma-separated list of strings that callers will use in flowSlug. For most flows this is a single keyword that matches the flow's purpose (welcome, cashback, entry).
  4. Save.

Add a chat widget to a landing

The platform doesn't bundle a chat widget yet — embed your own UI that posts to the public endpoints, or use the lightweight reference widget in your landing layout.

Use as a WhatsApp fallback

Combine web chat with the redirector: an outbound short link normally routes to a WhatsApp deep link (e.g. https://wa.me/...?text=hello), but when Meta health for the target channel is severity ≥ 2, the redirector swaps to the web-chat URL instead. Members never see a broken chat experience even during a WhatsApp outage.

This swap is automatic — the redirector reads the latest MetaAccountHealth snapshot for the channel and decides on the fly. No campaign change required.

Limits and gotchas

  • Anonymous and rate-limited. The public endpoints are open by design but rate-limited per IP via the WebChatPolicyName rate-limit policy.
  • Phone is optional at start. A flow can collect the phone with a set_phone_from_input action mid-conversation.
  • The legacy global-match bug — earlier versions resolved keywords globally and leaked flows across tenants when both used the same word. The current implementation resolves the tenant first; just make sure your hosting setup correctly populates Request.Host so the custom-domain path works.
  • Session state is in-memory + DB. Restarting the backend doesn't drop sessions — they're persisted.
  • No file uploads from the web side yet. A flow that needs an image upload (e.g. cashback claim) only works on WhatsApp today. Use send_form_link to redirect the member to a web form.