Update a widget
Changes a widget’s settings. Despite the PUT verb this is a partial update: only the fields you
send change, and at least one must be sent. Two exceptions to “merge” semantics:
brandingreplaces the stored branding object as a whole (send every branding field you want to keep;primary_coloris required inside it).allowed_originsreplaces the whole list.
Send greeting_message: null (or an empty string) to clear the greeting. The widget API key cannot
be rotated and the widget cannot be deactivated here; use DELETE /api/widgets/{id} to take it down.
Side effects. Updates the row, clears the cached widget list, the cached authenticated embed script and the runtime configuration cache, and writes an audit entry.
Consistency. Runtime endpoints (/widget/*) keep a per-instance copy of the configuration for up
to 30 seconds, so a new allowed_origins, rate_limit_rpm or voice_enabled can take that long to
apply everywhere. Browsers may cache the embed script for up to 5 minutes, so launcher colour and
position changes can take that long to appear on your site.
Idempotency. Safe to retry: sending the same body again leaves the same state (only
updated_at moves).
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.
Path parameters
Widget id. A value that is not a UUID returns 400 Invalid widget ID.
Request
Agent that answers visitors from now on. Must be a live agent of your workspace; otherwise 404 AGENT_NOT_FOUND and nothing changes.
Internal name. Trimmed; an empty or blank string is treated as not sent.
Replaces the whole list. Full origins (scheme, host, optional port); * never matches.
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.
Whether POST /widget/voice-session may be used for this widget.
First message the widget shows. Trimmed. null or an empty string clears it.
Requests per minute allowed per widget credential on the public /widget/* endpoints
(integer, 1 or more; 30 when the widget was created without one). Raising it does not
lift the workspace-wide cap of 300 requests/min across all of a workspace’s widgets,
which still applies on top.
Response
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.

