Create a widget
Creates a web-chat widget bound to one of your agents and mints its widget API key. The widget is
active immediately: embed it with the script from GET /widget-embed/{id}/embed.js, which
identifies the widget by its id and does not need the key.
The plaintext key is returned once, as plaintext_api_key (64 hex characters). Only an
HMAC-SHA256 digest is stored, so it cannot be retrieved again and there is no rotation endpoint. You
only need it to call the public /widget/* endpoints from a server you control, in the
x-widget-api-key header.
allowed_origins must list at least one full origin (for example https://www.example.com);
runtime calls from any other page are refused. agent_id must be a live agent of your workspace:
an id that matches no agent, a deleted agent, or an agent of another workspace is refused with 404
AGENT_NOT_FOUND (the three cases answer identically, so ids cannot be probed across workspaces).
Side effects. Inserts the widget row and writes an audit entry.
Idempotency. Not idempotent. Retrying after a timeout creates a second widget with a different
id and key; list with GET /api/widgets first if unsure, and delete the duplicate.
Webhook events. audit.log_recorded when you subscribe to it. See Webhooks.
Access
- Required scope:
write. - Rate limit: General API — 120 requests/min per workspace (200 on Growth, 300 on Business, 600 on Enterprise). See Rate limits.
- Plan: Available on every plan.
Authentication
Workspace API key: jl_ followed by 64 lowercase hex characters, created by the workspace owner in the
dashboard (Settings → API Keys) and sent as Authorization: Bearer jl_.... The plaintext is shown once,
at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys.
Operations restricted to admins or owners reject keys without the full scope with 403, and say so in
their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret —
that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds.
See Authentication.
Request
Agent that answers visitors. Must be a live agent of your workspace; otherwise 404 AGENT_NOT_FOUND.
Full origins (URLs) the widget may be embedded on. At least one is required
(At least one origin is required). Each entry must parse as a URL (Invalid url).
Widget look and copy. On write, primary_color is required whenever branding is sent, and the object
REPLACES the stored branding (it is not merged). Widgets created without branding store {}, which is
what POST /widget/init then returns.
Retired key (2026-09-15). logo_url is refused with 400 VALIDATION_FAILED —
El campo branding.logo_url ya no existe: el widget no dibuja ningun logo. It is also stripped from
every response, including the admin reads, POST /widget/init and the embed script, so a
read-modify-write client never sends it back by accident. The widget draws no logo.
First message the chat shows. Trimmed; an empty string is treated as absent (stored as null).
Requests per minute allowed per widget credential on the public /widget/* endpoints
(integer, 1 or more; defaults to 30). The workspace-wide cap of 300 requests/min across all of
a workspace’s widgets applies on top and is not configurable.
Response
Widget created. The only response that ever contains plaintext_api_key.
A web-chat widget configuration. Returned by every /api/widgets endpoint. Field names are snake_case.
The widget API key is never part of this object; the plaintext is returned only once, as
plaintext_api_key, when the widget is created.

