Changelog
Changes to the Smartbtn public API and webhooks are recorded below.
Support API: the chat asked for the mailbox -- 2026-10-03
Additive, stays in v1. chat.account gains email_requested (boolean, read-only): the chat itself has asked the customer for the account mailbox and is waiting for it, so the chat will mail the code as soon as the address arrives — an agent must not start another code flow meanwhile. Possible with link anonymous, and with none when an earlier binding lapsed; false while the chat is verified or a code is already out. Nothing existing changed.
Support API: a close-only scope -- 2026-10-02
Additive, stays in v1. New scope support:tickets:close: it grants POST /v1/support/tickets/{number}/close and nothing else — no claim, release, reopen, reply or read — for a backend whose only job is a customer's «question solved» button. That route now accepts support:write or support:tickets:close; tokens with support:write behave exactly as before. Like every support scope it works only for a token listed with support-api:configure --token, from an allowed IP. The registry now has 44 scopes (43 operational). OpenAPI gains x-scope-alternatives for the second scope. See Endpoints.
GET /v1/chats: find dialogs by client messages and text -- 2026-09-29
Additive, stays in v1. GET /v1/chats gains two optional filters. has_client_messages=1 keeps only the chats in which the visitor actually wrote — the same rule as chats_with_client_message on GET /v1/stats, every state and every handler included, so expired and AI-only chats are listed. q (2–100 characters) keeps only the chats in which a visible message contains that text; % and _ are taken literally. Without them the list is exactly what it was. Also spelled out in the reference, no behaviour change: what happens when an agent replies into an expired chat, that agent_id is required on a chat with no assigned agent, why chats_accepted_human can be 0 while chats have been handed to a person, and that avg_first_response_seconds supersedes avg_response_time_seconds for returning visitors.
Support-agent API: app-ticket account lifetime -- 2026-09-29
Stays in v1. The account of an app-ticket chat (link_source app_ticket) now has the contract's lifetime, ticket open + 7 days: chat.account.meduza_user_id is set only while the chat's most recent app ticket is open or was closed less than 7 days ago. POST /v1/ai/assistant/account-link/revoke now hides it until the next signed intake for that chat. Otherwise link is none and meduza_user_id null. Other chats are unchanged.
Knowledge base: writes with an assistant-bound key -- 2026-09-29
Fix, stays in v1. POST /v1/kb/rules and PATCH /v1/kb/rules/{id} answered 502 kb_embed_provider_failed ("No active AI credential found") for a widget whose only LLM key had been saved for one assistant, although that assistant kept answering in chats. Rules are now embedded with the widget-wide key when there is one, and otherwise with the key of the widget's enabled assistants (the default assistant first); the cabinet's rule editor, GET /v1/kb/status and the ai:kb-* commands resolve the key the same way. A 502 from the embedding provider now releases the idempotency key, as the reference always said it does, so the same request can be retried with the same key instead of answering 409. Documented, no behaviour change: source_ref, button_id, operator_id and chunk_index are read-only (422 kb_read_only_field), and a rule read with GET cannot be sent back as it is — send only content and doc_id.
Account link from the integrating backend -- 2026-09-29
Additive, stays in v1, switched off until the owner enables it. New: POST /v1/ai/assistant/account-link and /account-link/revoke — the integrating backend (same signed integration as /v1/ai/assistant/turn) binds a support chat to one of its accounts after verifying a proof itself, or revokes it. The support-agent API then shows, while that identity holds, chat.account.meduza_user_id, link verified, link_source (email_code, agent_code, cabinet, telegram_link, app_ticket) and the new fields identity_expires_at and regrant_needed; after it lapses or is revoked, link none. A code the customer types in the chat now also names the account when the backend reports it (link_source email_code, 24 h). Chats without an identity are unchanged. See Endpoints.
Support-agent API: app-ticket account -- 2026-09-28
Stays in v1. App-ticket chats (channel api_ticket) now name their account: chat.account.meduza_user_id is the application account the signed ticket intake filed the chat for, with link verified and the new field link_source app_ticket. When that account cannot be proven, link is the new value none (these chats used to read anonymous). Web-widget and messenger chats are unchanged. See Endpoints.
Support-agent API -- 2026-09-28
Additive, stays in v1. A new /v1/support resource group for automated support
agents: the ticket queue, chats with customer activity, a chat's messages labelled
client / ai / support / system, leases on chats,
closing and reopening tickets, and replies sent as the widget's configured human support operator
— text only, links limited to the widget's official link catalog, 201 only once the message is
stored. Three new scopes: support:read, support:reply (sensitive) and
support:write; the registry now has 43 scopes (42 operational). Off until the widget owner
enables it. Nothing existing changed. See Endpoints.
Support-agent API: e-mail code window -- 2026-09-28
Additive, stays in v1. chat.account gains code_pending, code_expires_at, last_code_result (verified / wrong / expired / attempts_exhausted / rate_limited / consumed / null) and last_code_at, so an agent can see whether the customer's e-mail code is still good before pointing at it. Existing fields are unchanged. See Endpoints.
Link buttons in messages -- 2026-09-23
Stays in v1. type: keyboard on
POST /v1/chats/{id}/messages used to be accepted and then shown as raw JSON on
every channel. It is now a real message with link buttons: drawn as buttons in the web widget
and the operator console, sent to Telegram as an inline keyboard, and as the text plus one
label: url line per button on every other messenger and in exports. Buttons are
now validated (label 1–64 characters, https-only URL, style
primary/secondary) and an invalid one answers 422
instead of being silently dropped; body is now required for this type. Also fixed:
a message sent through this endpoint into a chat that came from a messenger (Telegram, VK, ...)
now actually reaches the customer's messenger. Custom-channel deliveries carry the buttons as
message.buttons. See Endpoints.
Date-range history retrieval -- 2026-09-04
Additive, stays in v1. GET /v1/chats and
GET /v1/chats/{id}/messages now accept from/to,
filtering by creation date the same way GET /v1/stats already does. Neither
is required and neither changes the response shape when omitted -- an existing
integration that never sends them keeps working exactly as before. Before this, pulling
an old period meant paging the cursor backward from now through everything created since,
since there was no way to bound the query by date; the two range-index columns this uses
already existed for /v1/stats, so the fix is a query, not a schema change.
Separately, in the same area: a file/image message's
url in GET /v1/chats/{id}/messages is now resolved from the
stored attachment record instead of echoed from the raw message body. The old field was
frequently unusable -- literal HTML for any attachment uploaded through the widget itself,
rather than a link -- it is now a working, directly downloadable URL, plus the attachment's
original name. Nothing else about the message shape changed. See
Endpoints.
Chat acceptance attribution -- 2026-09-02
Additive, stays in v1. Chats now carry who answered them:
accepted_by, handled_by and handling on
GET /v1/chats and GET /v1/chats/{id}; seven new
chats_accepted* / chats_*_to_* metrics on
GET /v1/stats, three of them on /v1/stats/timeseries and
/v1/stats/channels; name, type and six
attribution metrics per agent on GET /v1/agents/stats and
GET /v1/agents/{id}/stats; operator_type on the
chat.accepted webhook, which now also fires for the AI operator's first
visible reply. One correction of an existing figure: chats_missed now counts
chats nobody answered. It used to count chats with no assigned owner, and since the
AI operator never becomes a chat's owner, every chat the AI answered was reported as
missed. Per-agent rating_average / rating_count are now attributed
to the agent handling the chat at rating time (for a chat the AI answered, the AI operator).
See Endpoints.
v1 -- initial public release -- 2026-07-10
First public release of /api/v1: bearer-token authentication with
per-token scopes, chats/messages/contacts/agents/tags/files/stats/channels
resources, outbound webhook subscriptions, the async external-AI-reply endpoint,
and the day-one third-party-migration compat routes under /compat/jivo. See
Endpoints and
Webhooks for the full reference
of what's live today, including which webhook event types are still
canary-disabled pending rollout.
v1 -- client-language AI phrases -- 2026-09-02
Additive. The phrases the platform itself sends to a customer on the AI path (hand-off to a
person, hand-off to the AI after the operator timeout, the appended handover notice, the
personal-data fail-safe) now always go out in the customer's language -- detected from the
customer's own messages, then the widget's default language, then English -- and can be
reworded per language on GET/PATCH/PUT /v1/ai/messages. The widget's default
language got its own small resource, GET/PUT /v1/widget/language. No existing
field or event changed. See Endpoints.
Docs -- bring-your-own-AI-key guide -- 2026-09-04
No API change. A new public guide, Bring your own AI
key, documents connecting the AI assistant to Claude, ChatGPT, DeepSeek or any other
OpenAI-compatible provider. The credential contract it documents is unchanged and was already
live: POST /v1/ai/credentials with provider one of
openai_compatible | anthropic | gemini |
gigachat, GET /v1/ai/credentials/{id}/models, and
PATCH /v1/ai/assistants/{id} for persona/system-prompt updates -- see
Endpoints.
Versioning policy
The API version is in the path (/v1, later /v2), not in
a header or query parameter. Going forward:
- Additive changes stay in
v1. A new field on an existing response, a new optional request parameter, a new endpoint, or a new webhook event type is not a breaking change -- clients are expected to ignore fields/events they don't recognize. These land as new entries on this page under av1heading, without a version bump. - Breaking changes get a new version. Renaming or removing a field, changing a field's type or meaning, renaming or removing a webhook event, or any change that could break a client that only knows the previous shape ships under
/v2instead, with a deprecation window for/v1announced here before it's turned off./v1keeps working unchanged until that window ends. - Webhook event names are frozen independently of the path version. Once an event type is enabled for a customer to subscribe to, its name and meaning do not change without a major version bump -- a name change would silently break every existing subscription filtering on that string.
- The signature header version (
sha256=v1:...) is independent of the API path version. It changes only if the signing scheme itself changes (e.g. a future move to a different digest algorithm), not when/v1becomes/v2.
Future breaking changes -- and the additive changes that don't warrant a version bump -- get their own dated entry above this policy section as they ship.
v1 — widget profiles and assistant learning — 2026-09-05. Added sparse desktop/mobile device_profiles, boolean icon-motion aliases, assistant greeting_i18n/quick_phrases_i18n, offline_outcome_mode and read-only learning_target. Learning writes and rollback now follow the selected assistant with target-scoped history/version inspection. API transcripts are UTF-8 without BOM; console export compatibility is retained. OpenAPI and both portal languages now describe idempotency headers, localization priority, offsets, bounds, data.hits and cache effects. Existing profile-free widgets retain their legacy behavior.