Send a widget message
Sends one visitor message in a session from POST /widget/init and returns the agent’s reply
synchronously. Operator replies typed later in the dashboard do not come back here; pick them up with
GET /widget/poll.
Send application/json for text. To attach one image (PNG, JPG, WEBP, GIF, HEIC, HEIF, AVIF, TIFF) or PDF of up
to 10 MB, send multipart/form-data with the file in file and the other fields as form fields;
message is still required. HEIC/AVIF/TIFF are converted and photos rotated upright before the agent
reads them. A file over 10 MB is cut off by the upload parser and currently fails with 500 rather than
the 413 body.
Credentials, origin check and per-minute limits are the same as POST /widget/init; see there.
Side effects. On the first message creates the webchat conversation (bound to the widget’s agent)
and links it to the session; stores the visitor message and the reply; calls the language model; draws
one AI message from the workspace’s monthly allowance when a model wrote the reply; if the session has
metadata.email, finds or creates the contact. The reply is also pushed to other open tabs of the
session over the widget WebSocket. When the workspace is out of AI messages the visitor gets a neutral
503 and the workspace owner receives an in-app notification (once per day). No webhook event is emitted
for the message itself.
Idempotency. Not idempotent. A retry after a timeout stores the visitor message again, generates
a second reply and spends another AI message and another unit of the daily cap. De-duplicate replies
by message_id.
Access
- Required scope: None;
jl_API keys are not used. The widget credential plus a matchingx-widget-parent-originauthorise the call. - Rate limit: Widget public — 60 requests/min per IP, the widget’s
rate_limit_rpmper credential, 300 requests/min per workspace, plus a daily cap on widget messages per workspace (5,000 by default, resets at 00:00 UTC). See Rate limits. - Plan: Available on every plan. Replies draw from the plan’s AI-message allowance.
Headers
Secret widget API key (plaintext_api_key from POST /api/widgets). Takes precedence over
x-widget-id and wid. Send one of the three. Never expose it in a browser.
Public widget id, the credential the embed script uses. Used when x-widget-api-key is absent.
Origin of the page embedding the widget. Must match one of the widget’s allowed_origins; see POST /widget/init.
Query parameters
Request
Session id returned by POST /widget/init.
Display name the UI shows for the agent (from branding.agent_names); the reply is signed with it and it is saved on the session.
Primary language subtag of the visitor’s UI (es, en); used as the reply language and saved on the session.
Signed identity used only by Jelliu’s own in-app support widget. Integrations do not need it; an invalid token, or one for another workspace, is ignored.
multipart/form-data only. One image (PNG, JPG, WEBP, GIF, HEIC, HEIF, AVIF, TIFF) or PDF, up to 10 MB.

