Where to start
| You want to … | Go to |
|---|---|
| Use the admin panel — build flows, manage connections, read history, run analytics | Admin panel guide |
| Configure the chat widget — keys, allowed origins, intents, quick questions | Widget settings |
| Read quick-question prompts or public widget config without a session | Public read API |
| Understand the moving parts (widget key, session, intent, execution, block, wait token, status) | Concepts |
| Walk through the full conversation lifecycle from session-open to completed | Lifecycle |
Know what to render for each block.type returned by the flow | Blocks |
Look up an error code and decide retry vs. abort | Errors |
| Measure conversions, chat engagement, and which chats lead to a sale | Concepts → Goals & telemetry |
| Build, export, pin, or schedule analytics reports in the admin | Analytics Hub |
| Drive analytics, flows, and connections from an AI agent over JSON-RPC | MCP API |
| Report server-side conversions or read engine state from your backend | Engine API |
| Receive chat session and execution events on your own endpoint | Webhooks |
| Get the precise contract — fields, status codes, JSON shapes | API reference |
The endpoints
Chat — drive a conversation against a published flow:?publicKey=, an X-Comerix-Public-Key header, or a publicKey body field.
Uploads require a ?field= query parameter naming the form’s file field and a
multipart file part. See Forms in the admin to build
and publish a form.
The two schema reads differ in one thing: the plain GET counts a “mount”
toward the key’s usage metering and is uncached; GET …/schema never writes
and is privately cacheable (max-age=60, private + ETag/If-None-Match →
304) — use it when an embed polls or refreshes the schema. Full contract:
Public read API → Form schema.
Published reads — anonymous, cacheable GETs for bootstrapping the widget
UI before (or without) a session:
?publicKey= or
X-Comerix-Public-Key), are shared-cacheable (Cache-Control +
ETag/If-None-Match → 304), and report whether they were served from the
published edge document via X-Edge-Source. The forms schema read above
belongs to the same family — same key, same ETag/X-Edge-Source
conventions — but is privately cacheable. Full contract:
Public read API.
Telemetry events feed the goals & conversions and chat-engagement
analytics — see Concepts → Goals, conversions & telemetry.
Sales that complete after the chat ends are reported server-side via the
Engine API → Conversions endpoint.
Replies carry token usageEvery chat
reply now includes a tokenUsage object when an LLM ran during
that turn — prompt_tokens, completion_tokens, total_tokens, model,
cost_micros, and a convenience cost_usd. The same figures ride the
chat.execution.updated webhook and roll up into
the Token spend analytics.Which flow does the widget talk to?
A widget key permits one or more intents (one intent ⇄ one published flow). Two modes:--intent=<name>(repeatable) oncomerix:widget-key:create→ explicit allow-list.--all-intentsflag → permission to trigger any of the tenant’s currently-published intents.
--all-intents.
The widget learns its allowed intents from the session response:
intentName in the request body — the server checks it against this set and returns 403 intent_not_allowed if it’s outside, or 404 intent_not_matched if no published flow exists for it.
Resume calls (form submissions) don’t carry intentName — the engine already knows which flow the execution belongs to.
60-second quick start
-
Tenant admin issues a widget key (one-time):
-
Widget opens a session (once per visitor):
Response includes the
sessionTokenplus the list of intents the widget may trigger (intersected with what’s currently published): -
User types a message — widget picks the intent and calls
/messages: -
Flow asks for input — reply comes back with
status: waiting_input,blocks(render them), and awaitToken+executionId. Widget collects the form values and calls/messagesagain, this time with the wait info: -
Repeat step 4 until
statusbecomescompleted(success),failed, oraborted. The same/messagesendpoint handles both trigger and resume. -
When a node dispatches async work the reply comes back with
status: waiting_time— the engine paused while a queue worker does its job. The widget pollsGET /executions/{executionId}every 1–2 s until status transitions back towaiting_inputorcompleted/failed.
CORS in one sentence
The widget key carries anallowedOrigins list. A request from any other
origin is rejected with 403 origin_not_allowed and no CORS headers, so
the browser blocks the body from being read by attacker JS.