Chat is web-component + JavaScript first today — there is no native
mobile/polyglot chat SDK. To drive chat from another platform, speak the
envelope protocol over a raw MoQT client. The
server-side token mint shown here is part of the control-plane API.
How a conversation is wired
Every conversation lives under three MoQT tracks atchat/<org>/<conv>:
| Track | Direction | Who uses it |
|---|---|---|
client | visitor → engine | the widget publishes visitor messages here |
server | engine → visitor | the widget subscribes here (its only read) |
agent | human agent → engine | relayed onto server, so the widget has one read |
kind is one of message | typing | form | form_result | event. The full
schema is in Widget & API.
Recipe 1 — Support widget with AI-to-human handoff
A visitor opens your site, the widget greets them with an AI text agent, and if they ask for a person the conversation is offered to a human agent who sees the entire transcript. Because the human joins the same conversation (same tracks), no history is lost.Design the flow in the console
In the console’s visual flow builder — the same step engine that powers voice
IVR — build a flow named
support:- Announce a greeting (
"You're chatting with our assistant."). - Queue to skill → AI text agent. Point the step at a text conversation
DAG (the agent runtime running in text mode). It answers on the
servertrack. - Escalation branch. When the visitor’s intent is “talk to a human” (or
the AI calls a
handofftool), queue to skill → human. The visitor keeps chatting on the same conversation; the engine offers it to an available human agent, with RONA (redirect-on-no-answer) re-offer if the first agent doesn’t pick up.
Mint a token on your server
The widget calls a URL on your server to get a short-lived token. Your
server holds the API key and asks the control-plane API to mint a token
scoped to exactly one conversation’s tracks.The returned token carries an
ns claim of chat/acme/<conv>/* — the widget
can only publish and subscribe within that one conversation.Drop the web component on the page
Load the widget script and place the element. The tag is your brand name
lowercased +
-chat. It fetches a token from token-endpoint, opens the
connection, and runs the support flow.index.html
Your workspace id. Must match the token the endpoint mints.
A URL on your server that returns
{ token, conversationId, relayUrl }.
The widget calls it when it first opens.The flow to run. Defaults to the workspace’s default chat flow.
auto tries QUIC and falls back to a secure WebSocket; wss forces the
fallback (useful behind proxies that block UDP).Header text and launcher placement (
bottom-right, bottom-left).Staff the human side
Human agents sign in on the agent portal in the console. Offered
conversations appear with the transcript pre-loaded; an agent accepts, and
their replies flow onto the
agent track, which the engine relays to
server so the widget renders them inline. Set each agent’s concurrent chat
capacity so one person can cover several conversations.What the handoff looks like on the wire
When the flow crosses the escalation branch, the engine emits anevent
envelope on the server track so the widget can show a status line, then the
human’s messages arrive as ordinary message envelopes:
The human sees the transcript — every visitor and AI turn on the
conversation. What does not transfer is the AI agent’s hidden state (its
tool-call scratchpad); the human works from the visible conversation, exactly
as the visitor sees it.
Recipe 2 — Lead-capture form that routes by result
Here the flow presents a form, blocks on a validated result, and then branches: high-budget leads go straight to a human sales queue; everyone else continues with the AI text agent. You write no form HTML — the widget renders aform envelope natively and returns a form_result.
Design the form and the branch
Build a flow named
lead-capture:- Announce a one-line intro.
- Present a form and await a validated result. The engine sends a
formenvelope and will not advance until the widget returns aform_resultthat passes the field validation you set (required fields, email format). - Branch on the result. Route by a field value — e.g.
budget == "$5k+"→ queue to skill → human (sales); otherwise → queue to skill → AI text agent to answer questions and book a demo.
The form round-trip
The engine sends aform envelope on the server track; the widget renders the
fields and, on submit, publishes a form_result on the client track. The flow
validates it and continues.
budget, this visitor is queued to the human
sales skill; a $1k–5k visitor would continue with the AI text agent instead.
Validation is enforced server-side — if email is malformed or budget is
missing, the flow re-presents the form rather than advancing.
Drive it from a custom client
If you can’t use the web component (a native app, a kiosk, a server-to-server bot), open the same three tracks over a raw MoQT client and speak the envelope protocol yourself: publishmessage / form_result on client, subscribe
server, and honor typing / event / form. The wire schema and a minimal
client are in Widget & API.
Related
Widget & API
Every widget attribute, the full envelope schema, and a raw-MoQT client.
Chat overview
How chat rides MoQT and shares the flow engine with voice.
Cookbook
Short, single-purpose snippets: embed, form, route, hand off.
Authentication
How short-lived, namespace-scoped tokens are minted and verified.