<telequick-chat> web component: it mints a conversation-scoped
token, opens a real-time session (QUIC first, WebSocket fallback), and drives the
same visual flow / step engine as TeleQuick Voice — announcements, waits
with queue position, forms, and skill queues — plus AI text agents and human
handoff.
Chat is widget- and JS-first today. There is no polyglot SDK for chat: you
embed the web component and configure it, or speak the
envelope protocol directly from a custom client
over raw MoQT. Server-side token minting uses your normal control-plane
credentials.
Add chat to a webpage
Drop the widget on any page in two moves: mint a conversation-scoped token on your server (never ship your API key to the browser), then render the element with that token.Mint a scoped token server-side
Exchange your server credential for a short-lived token bound to one
conversation namespace (
chat/<org>/<conv>). Do this in a backend route and
hand the result to the page.Your organization / workspace id. Scopes the conversation namespace.
Id of the flow (built in the console with the same step engine as voice)
the conversation runs. Omit to use your default flow.
Token lifetime in seconds. The widget re-mints on expiry via your endpoint.
support) runs on
connect — greet, collect, queue — exactly as you built it in the console.
Present a form
Forms are flow-driven: a step in your flow presents a form and blocks until the visitor submits a validform_result. The widget renders the fields, does
client-side validation, and returns the structured result to the engine — no
front-end code required. Add a form step to the flow the token points at:
flow: support (excerpt)
form envelope; the widget renders it and, on submit,
publishes a form_result envelope that the flow validates before advancing. The
captured values are available to downstream steps and to the agent who picks up.
Building forms with a custom (non-widget) client? You receive the
form
envelope on the server track and publish a matching form_result on the
client track yourself — see the
envelope protocol.Route to a skill / queue
Aqueue step places the conversation into a skill queue and announces position
while the visitor waits. The same skill can be staffed by human agents, an AI
text agent, or both — routing picks whoever is eligible and available.
Attach an AI text agent
Point a queue step — or the whole flow — at an AI text agent to answer automatically. It is the same agent runtime as voice, in text mode: the same tools, knowledge, and DAG, driven by text turns instead of audio.message envelopes and can raise
a typing indicator between turns. When it hits a tool or policy that requires a
person, it escalates — see the next recipe.
Hand off to a human
Escalation is a flow transition: the AI agent (or aswitch on its outcome)
routes the live conversation into a human skill queue. The conversation keeps
its id, so the visitor’s history, the captured form, and the AI transcript are
all in front of the human when they accept.
flow: AI first, human on escalate
The AI agent decides a human is needed
Any tool, guardrail, or explicit “talk to a person” intent transitions the
flow to the
to-human label.The conversation queues to a human skill
It is offered on the agent console. A human agent can hold several
concurrent chats, so pickup is fast; unanswered offers re-offer per your
RONA policy.
The full agent-side experience (accepting offers, the multi-chat workstation,
what the human sees on pickup) lives in the console, not the widget. Media
escalation from a text chat to a voice/video call is on the roadmap; today
handoff is text-to-text.
Send a file attachment
Attachments ride out of band: you upload the raw bytes over HTTPS, get back an attachment meta, then publish a normalmessage envelope that references it.
The bytes never travel through the real-time session — only the small meta does.
On the widget this is zero-code: the paperclip button, drag-and-drop, and a
multi-file picker (
<input accept>) upload and attach for you. The recipe below
is for custom clients speaking the
envelope protocol directly.Upload the bytes, get an attachment meta
POST the raw file bytes to the upload endpoint with the session token
(the same conversation-scoped token the widget/client already holds). Name
the file in the x-cc-filename header and set Content-Type to its MIME
type. The endpoint enforces an allowed-MIME allowlist and a max size and
rejects anything else.Original file name. Preserved in the meta and used to build the download URL.
The file’s MIME type. Must be on the allowed list or the upload is rejected.
Attachment id, unique within the conversation.
File name as uploaded.
Byte size the engine recorded.
Stored MIME type.
Download URL for the bytes, served at
GET /v1/chat/attachment/<conv>/<id>/<name>. Object storage sits behind it.Publish a message envelope that carries the meta
Send a normal
message envelope with data.attachments set to an array of
the metas you got back. text is optional — an attachment-only message
can leave it empty. Attach several files by uploading each, then listing all
their metas.The engine emits a
chat.file.uploaded event { role, count } and records
"[file: <names>]" in the transcript, so an attached AI text agent has
context about what was shared even though it can’t read the bytes.React to a message
Everymessage envelope carries a mid — an author-owned message id, unique
within the conversation, that the engine stamps and relays. Reactions (and quoted
replies via reply_to) address a message by its mid. To react, publish a
reaction envelope with data { op, emoji, target_mid }.
On the widget this is zero-code: the hover quick-reaction strip and the emoji
picker publish these envelopes for you, and reaction pills show live counts. The
recipe below is for custom clients.
Add the reaction, or remove one you previously added.
The emoji to attach, e.g.
"👍", "🎉", "❤️".The
mid of the message you’re reacting to.chat.reaction
event { role }. Reaction envelopes are their own kind — the full set is
message | typing | form | form_result | reaction | event, documented in the
envelope protocol.
Custom theme
Match the widget to your brand with attributes for the common knobs and CSS::part() selectors for deep styling. The widget is a real custom element, so
its shadow parts are stylable from your page CSS.
Color scheme.
auto follows the visitor’s prefers-color-scheme.Primary accent used for the launcher, buttons, and visitor bubbles.
Corner radius in pixels for the panel and bubbles.
Docked corner for the floating launcher.
Mount programmatically
Skip the declarative markup and create the widget from JavaScript — for SPAs, consent-gated loading, or opening the panel on your own button. The element exposesopen(), close(), and a config object.
For a fully custom UI (no widget at all), drop to the wire: subscribe the
server track and publish client envelopes yourself over raw MoQT. The
message, typing, form, and event envelope shapes are documented in
Widget & API.Related
Widget & envelope protocol
Every widget attribute and the JSON envelope wire for custom clients.
Chat overview
How conversations, tracks, flows, and agents fit together.
End-to-end recipes
Full builds: a support widget with AI-to-human handoff and lead capture.
Deployment models
Where the engine runs and how to make chat highly available.