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:
- Explicit
tenantSlugin the request body. - Custom domain — if
Request.Hostmatches a tenant'sWhiteLabelConfig.CustomDomain, that tenant is selected. Abp-TenantIdheader (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
- Open the flow in Communications → Flows.
- Make sure it's Active.
- 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). - 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
WebChatPolicyNamerate-limit policy. - Phone is optional at start. A flow can collect the phone with a
set_phone_from_inputaction 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.Hostso 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_linkto redirect the member to a web form.