When to use it
Support / sales chat
Put a chat bubble on your marketing site or app. It greets visitors and
answers with an AI text agent. It escalates to a human when necessary.
One flow, phone + chat
Reuse the announcements, forms, and skill queues that you built for voice.
Voice and chat share the step engine. Chat is a text-mode surface over it.
Lead capture
Present a form in the middle of a conversation. The flow blocks until the
visitor returns a validated result. You get structured intake, and the
visitor does not leave the chat.
Concurrent human agents
One human agent handles several conversations at the same time from the
console. Routing is skill-based. If the agent misses an offer, the engine
offers the conversation again.
Files & reactions
Visitors and agents attach files (images and documents). They react to
messages with emoji or a quote-reply. The AI text agent sees uploaded files
as context.
Embed the widget
The web component tag is your brand name in lowercase, plus-chat. The
element that you place on the page is <clutchcall-chat>.
1
Load the widget script
Add the loader
<script type="module"> from your workspace’s widget URL to
the page <head>. The script registers the custom element and defines
<clutchcall-chat>.2
Place the element
Put
<clutchcall-chat org="…" flow="…"> anywhere in the body. The
widget renders a launcher bubble. When the visitor opens it, the widget
renders a chat panel.3
It connects on its own
When the visitor opens it, the widget mints a namespace-scoped token.
The widget opens a MoQT session to the relay. The transport is QUIC
first, with a WSS fallback. The widget then subscribes to its
conversation’s
server track. You do not write connection code.string
required
Your workspace or organization id. It scopes the conversation namespace and
the minted token.
string
required
The published flow (step-engine graph) that drives the conversation. The flow
contains the announcements, the forms, and the queue-to-skill step. You
author it in the flow builder, the same builder that voice uses.
string
default:"auto"
light, dark, or auto. This attribute is cosmetic. It does not change
routing.The widget subscribes to exactly one track (
server). It publishes to
one track (client). Everything that the visitor sees arrives on that
single server subscription: AI replies, human replies, system announcements,
and forms. The UI never reconciles multiple streams. See
Tracks.The three tracks
The address of each conversation ischat/<org>/<conv>. Each conversation
carries three MoQT tracks. The split keeps the widget’s job simple: publish one
track and subscribe to one track. A human agent can join without a change on
the widget side.
A human agent publishes on
agent. The engine relays those envelopes onto
server. That is why the widget needs only one subscription. AI replies and
human replies both arrive on server. The transport layer does not tell them
apart. The role field in the envelope identifies the author.
The envelope protocol
Every MoQT object on a chat track is one JSON envelope. This is the wire contract for a custom client. Speak it if you build your own UI over raw MoQT instead of the widget.number
required
Envelope version. Currently
1.number
required
A monotonic sequence number per track. Use it to order envelopes and to find
gaps.
number
required
The epoch timestamp in milliseconds. The sender sets it.
string
required
One of
message · typing · form · form_result · reaction · event.string
required
The author. Examples:
user, agent (AI or human), system.object
required
The payload for the given kind: message text, a form schema, a submitted
result, or an event body.
Message ids, attachments, and replies
Thedata of a message envelope carries more fields than text:
string
An author-owned message id. It is unique in the conversation. The engine
stamps it and relays it. Reactions and quoted replies address a message by
its
mid.array
Zero or more attachment metas for files sent with this message. Each meta is
{ id, name, size, mime, url }. An attachment-only message can have empty
text. See File uploads.object
A quoted reply. The object
{ mid, preview } points at the quoted message.File uploads
Visitors and agents can attach images and documents to a message. The file bytes travel out-of-band, not through MoQT. Upload the bytes over HTTPS. The response is an attachment meta. Then publish a normalmessage envelope
that references the meta.
1
POST the bytes
Send the raw file bytes to the control-plane API with the session token.
The server permits only an allowed set of MIME types and a maximum size. It
rejects all other uploads.
2
Read the attachment meta
The response is the attachment meta. Store the whole object. You attach it
to the message verbatim.
3
Publish a message that references it
Publish a normal
message envelope. Set data.attachments to an array of
metas. For an attachment-only message, the text can be empty.GET /v1/chat/attachment/<conv>/<id>/<name>. Object storage serves the bytes.
On upload, the engine emits a
chat.file.uploaded event { role, count }. The
transcript records "[file: <names>]". Thus an AI text agent has context
about the file, although the bytes never crossed the AI’s text channel.Reactions
With emoji reactions and quoted replies, each side can annotate a specific message. Themid identifies the
target message. A reaction is its own envelope kind:
string
required
add or remove.string
required
The emoji to apply.
string
required
The
mid of the target message.chat.reaction
event { role }.
On the widget, these features work with no code. The built-in UX includes a
paperclip attach button, drag-and-drop, a multi-file picker (with
accept
filtering), an emoji picker, a hover quick-reaction strip, and reaction pills
that show counts. The envelope and upload details above are for custom
clients and for readers who study the wire. See
Widget & API and the
Cookbook for procedures.Same flow engine as voice IVR
Every conversation runs through the same visual flow builder and step engine as voice. You do not learn a second product. The steps that you know from IVR apply directly to text:- Announcements — send a scripted
message, for example a greeting, business hours, or a policy notice. - Waits + queue position — hold the visitor and show their queue position
while they wait for an agent. The engine delivers the position as
eventenvelopes. - Present a form — emit a
formand block until a validatedform_resultarrives. Use this for lead capture and structured intake. - Queue to a skill — route the conversation to a skill queue. This is the same model as an ACD queue on the voice side.
- AI text agent
- Human agent
The engine hands the conversation to a text conversation DAG. This is
the same agent runtime as voice, in text mode instead of speech. The
agent answers and can call tools. It can also decide to escalate, and then
it queues the conversation to a human skill.
Honest limits
Related
Widget & API
Embed the widget. Configure its attributes. Speak the envelope protocol
from a custom client.
Cookbook
Task snippets: embed on a page, present a form, route to a skill, hand off
to a human.
Recipes
End-to-end builds: a support widget with AI-to-human handoff, and a
lead-capture form.
Agent runtime
The same runtime that the AI text agent uses, here in text mode.
Human handoff
How escalation to a human works across modalities.
Skill queues (ACD)
The skill-based routing model that the queue-to-skill step shares with
voice.

