Skip to navigation

Start a widget session

View as Markdown

Opens (or resumes) a visitor session and returns what the chat UI needs to render: greeting, branding and whether voice is on. Call it once when the chat loads, then use the returned session_id with POST /widget/message, GET /widget/poll and GET /widget/history. The standard embed script does all of this for you.

Credentials. This is a public endpoint. It does not accept a dashboard session or a jl_ API key. Name the widget with exactly one of these, checked in this order:

  1. x-widget-api-key header: the secret plaintext_api_key (server-side callers only);
  2. x-widget-id header: the public widget id (what the embed uses);
  3. wid query parameter: the public widget id.

The API key is never accepted in the query string. A value that looks like a UUID is treated as a widget id, whichever header carries it. Every call must also send x-widget-parent-origin with the origin of the page that embeds the widget; it must match one of the widget’s allowed_origins (scheme and port exactly, hostname modulo one leading www.). The check does not use the browser’s Origin header, and CORS is open (Access-Control-Allow-Origin reflects any origin, no credentials).

Sessions. Sessions are keyed by visitor_id. If the same visitor had a session on this widget that was active in the last 30 days, it is returned with resumed: true and any new metadata is merged into it (keys are added or overwritten, never removed); otherwise a new session is created. Send metadata.email (and metadata.name) to link the visitor’s conversation to a contact.

Side effects. Creates or updates a widget_sessions row (with the caller’s IP and user agent on creation). No conversation is created until the first message; no AI usage is recorded.

Idempotency. Safe to retry with the same visitor_id: a retry resumes the session the first call created. Two truly concurrent first calls for a new visitor can create two sessions.

Access

  • Required scope: None; jl_ API keys are not used. The widget credential plus a matching x-widget-parent-origin authorise the call.
  • Rate limit: Widget public — 60 requests/min per IP, plus the widget’s rate_limit_rpm (default 30) per credential and 300 requests/min per workspace across all its widgets. See Rate limits.
  • Plan: Available on every plan.

Headers

x-widget-api-keystringOptionalformat: "^[0-9a-f]{64}$"

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.

x-widget-idstringOptionalformat: "uuid"

Public widget id, the credential the embed script uses. Used when x-widget-api-key is absent.

x-widget-parent-originstringRequiredformat: "uri"

Origin (or any URL; only its origin is used) of the page embedding the widget. Must match one of the widget’s allowed_origins. Missing returns 403; an unparseable value returns 403 Invalid parent origin. Only the dashboard preview, which sends a short-lived x-widget-preview-token, may omit it.

Query parameters

widstringOptionalformat: "uuid"
Public widget id as a query parameter. Used when neither header is present.

Request

This endpoint expects an object.
visitor_idstringRequired>=1 character

Stable id the embedding page keeps for this visitor (the embed stores a UUID in localStorage). Reusing it within 30 days resumes the same session and conversation.

metadatamap from strings to anyOptional

Free-form visitor data stored on the session (merged on resume). email links the conversation to a contact (created in the workspace’s manual-conversations campaign if none matches, case-insensitively); name fills the contact’s name when it is empty.

Response

Session created or resumed (both return 201).

dataobject

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
429
Too Many Requests Error
503
Service Unavailable Error