Ta strona jest publikowana po angielsku i ukraińsku; poniżej wersja angielska.
POST /message: chat over HTTP
For developers, in code: the synchronous chat endpoint for a custom integration — request fields, the response with sources, actions and suggestions, and every status it returns.
POST /message answers one visitor message and returns the whole answer at once. The widget uses
the WebSocket instead (WebSocket); /message is for a server-side
integration or a front end that does not need streaming. Page actions — which need a mid-turn
round trip to the browser — are not available on it.
POST /message
X-Widget-Key: wk_…
Content-Type: application/json
{ "agent_code": "default", "widget_code": "default",
"message": "What is your returns policy?",
"conversation_id": null, "page_url": "https://shop.example/cart", "page_lang": "en" }
Request
| Field | Type | Required | Meaning |
|---|---|---|---|
agent_code |
string | yes | the agent within the key’s site |
message |
string, non-empty | yes | the visitor’s text |
conversation_id |
UUID or null | resume a conversation; omit to start one | |
widget_code |
string | which widget is chatting (several may share an agent) | |
page_url |
string | the page the visitor is on; matched against app-screen routes | |
page_lang |
string | <html lang> — the reply-language fallback when the message’s language cannot be told |
|
session_id |
string | a browsing-session id, for analytics | |
external_user_id |
string | an id on your side; not authentication | |
user_token |
string | the logged-in user’s token, relayed to tools as {{user}}; never stored; over 8,192 characters it is ignored |
|
spoken |
boolean | the answer will be read aloud — keep it short, and the turn costs the voice surcharge | |
page_route, page_params |
string, object | a declared screen (/orders/{id}, { id }) when the URL cannot name it; route ≤ 255, ≤ 20 params |
|
visitor |
object | arrival context, read only on the frame that creates a conversation: referrer, utm_source, utm_medium, utm_campaign, browser_language, timezone, widget_language — each a string, clipped to 2,000 |
|
page |
object | the page-actions hint: readable, actionable, counts, submit_policy — meaningful on the socket only |
|
suppress_teaser |
boolean | legacy; skip teaser routing this turn |
Response
{
"conversation_id": "…",
"answer": "You can return any item within 30 days …",
"sources": [
{ "source_id": "…", "title": "Returns", "description": "…", "url": "…", "score": 0.82 }
],
"actions": [],
"nav_suggestions": [
{ "type": "navigate", "url": "…", "label": "Open: Returns", "source_id": "…" }
],
"metadata": {
"tags": [],
"language": "en",
"chunks_retrieved": 3,
"top_score": 0.82,
"search_calls": 1,
"had_insufficient_context": false,
"model": "claude-haiku-5-5"
}
}
| Field | Meaning |
|---|---|
answer |
Markdown; the widget renders a safe subset |
sources[] |
citations: the page’s title and description (its own metadata), the URL, the score |
actions[] |
what the turn asks the host to do — Actions. A navigate here is acted on now; one with confirm: true is a question waiting for a yes |
nav_suggestions[] |
at most one page worth opening, offered as a plate — never navigated to without a click |
metadata.language |
the language the answer is in |
metadata.had_insufficient_context |
the knowledge base did not answer: the search found nothing above the floor, or the assistant itself judged the pages did not address the question |
metadata.search_calls |
how many searches the turn made (0 for a greeting) |
Keys the pydantic models do not declare are dropped on this endpoint — referral_kind on an
action, relevance on a citation; the socket sends them. A turn at the monthly cap still
returns 200: answer is the limit message and the lists are empty.
Statuses
| Status | When | detail |
|---|---|---|
401 |
missing or unknown key | Missing widget key / Invalid widget key |
403 |
inactive key, origin not allowed, or the widget is switched off | Widget key is inactive / Origin not allowed / This assistant is switched off |
404 |
unknown agent, or a conversation that is not this site’s | Unknown agent for this key / Conversation not found |
409 |
the widget has no agent assigned (empty agent_code) |
This widget has no agent assigned |
422 |
body validation, or the model declined to answer this message | the pydantic error list / The assistant declined to answer this message. |
429 |
the account’s per-minute limit, or this visitor’s per-minute or daily one | Rate limit exceeded. Please slow down. |
503 |
the model failed | The assistant is temporarily unavailable. Please try again. |
Continuing a conversation
Pass back the conversation_id you received. The server keeps the conversation’s memory and the
pending offers — a page it asked about, a held event — so a reply of «yes» is judged against the
offer. A conversation_id the server no longer knows is a 404; start fresh.