Chat sessions and widget
A chat session is a conversation between one visitor and one CHAT agent. Your page or your
backend opens it, sends the visitor’s messages one at a time, and reads the agent’s reply as a
stream of events. When the visitor leaves, you end the session and, if you like, rate it.
The same five calls exist twice:
The public calls need the matching scope on the key (chat:init, chat:stream, chat:status,
chat:rate, chat:end) and a page whose origin is in the key’s domains. The examples below use
the public form; swap the prefix and the header for the other.
Start the session
Both fields are optional: dynamic_variables are strings the agent’s prompts can use, and
ip_address lets a backend pass the visitor’s address along. Keep the call_id; every other
call needs it. If the agent opens the conversation, its first message is already in
chat_history. When reCAPTCHA is enabled on the key, this call also needs a g-token header.
Send a message and stream the reply
The response is application/x-ndjson: one JSON object per line, each with an event and a
data object, until the reply is complete.
Render message_chunk events as they arrive and replace them with message_complete, which
carries the whole message. Other events tell you what the agent is doing:
One message at a time: sending another stream while a reply is in progress returns 410
with STREAM_BUSY.
Check the session
GET …/chat/{call_id}/status returns { "status": "IN_PROGRESS" }. A session is
REGISTERED after init, IN_PROGRESS once messages flow, ENDED after end or after the
agent’s idle timeout, and ERROR if it failed. A page that reloads can use this to decide
whether to resume the session or start a new one.
Errors you will meet
Rate limits are 20 requests per minute per public key on each of init, stream, end and
rate, and 500 per minute per entity on init and stream; see
API conventions.
Widget configuration
The embeddable widget reads its look and behaviour from the agent’s widget configuration, a free-form JSON document you control:
PUT creates or replaces the configuration and needs the WRITER role; GET /ai-agents/{agent_id}/widget-config returns it with id, ai_agent_id, entity_id, created,
updated and presigned_urls for any assets it references.
The widget itself fetches it from the browser with the public key:
The response carries an ETag and short-lived Cache-Control; send the tag back in
If-None-Match and you get 304 while nothing changed. The key needs the widget-config:read
scope.