Разработчику

Подпись посетителя

Ваш сервер подписывает токен, и чат знает, какой вошедший посетитель пишет.

На странице

Если посетители входят в аккаунт на вашем сайте, ваш сервер может сказать чату, кто пишет. Тогда:

  • операторы видят аккаунт и поля, которые вы передали;
  • посетитель находит свой разговор на любом устройстве и на любом домене проекта.

Без подписи браузер хранит разговор отдельно для каждого сайта. На новом устройстве или зеркале посетитель начинает заново.

Как это работает

  1. Ваш сервер подписывает токен для вошедшего пользователя секретом подписи проекта.
  2. Страница передаёт токен чату: через data-identity на теге или identify(token).
  3. Виджет отправляет токен в POST https://api.tolkly.io/v1/projects/<project>/identify. Сервер проверяет его и говорит, какой разговор принадлежит посетителю: тот, что в этом браузере, а если его нет — последний открытый разговор посетителя.

Сам виджет ничего не проверяет. Если сервер отклонил токен, ему не доверяют даже частично: чат работает как анонимный.

Токен

Токен — это JWT с подписью HS256. Сервер всегда читает алгоритм как HS256, что бы ни стояло в заголовке. Если в заголовке другой алгоритм, включая none, токен отклоняется.

ПолеОбязательноЧто это
subдаID пользователя у вас, строка (число принимается как строка), до 200 символов. С более длинным токен отклоняется.
nameнетИмя, которое видят операторы, до 120 символов.
emailнетОтбрасывается, если не похоже на почту.
phoneнетОтбрасывается, если не похоже на номер телефона.
fieldsнетОбъект с полями, которые объявил проект (ниже).
expнетСрок действия в секундах от начала эпохи. Без него токен действует, пока действует секрет.

exp проверяется с запасом в 60 секунд. Так немного отстающие часы не отклонят свежий токен. Токен длиннее 8192 символов отклоняется без чтения.

Содержимое токена подписано, но не зашифровано: посетитель может прочитать его на странице. Передавайте только то, что ему можно видеть.

Поля

Поля у каждого проекта свои: номер счёта, статус KYC, VIP-уровень, ссылка на пользователя в вашей админке. Каждое поле проект объявляет с ключом и типом. Необъявленные поля в fields отбрасываются, как и значения неверного типа. Поля объявляют владельцы и администраторы компании.

ТипПринимает
textстроку до 500 символов (число принимается как текст)
numberчисло или строку с числом
dateYYYY-MM-DD или полное время в ISO 8601
listмассив строк или чисел, каждое до 100 символов; сохраняются первые 20. Одно значение считается одним элементом. Если хоть один элемент пустой, слишком длинный или другого типа, отбрасывается весь список.
linkURL http: или https:, до 2000 символов
booleantrue или false (а также "true", "false", 1, 0)

Поля объявляются в разделе проекта «Установка» › «Дополнительно», блок «Поля посетителя»: название, которое видят операторы, ключ, который пишет ваш сервер, тип и показывать ли значение операторам. Ключ после создания не меняется: ваш сервер уже его присылает, поэтому новый ключ — новое поле. Выключите «Показывать операторам» для значения, которое нужно только правилам, например оценки риска.

Секрет

Владельцы и администраторы компании находят его в разделе проекта «Установка»: «Дополнительно» › блок «Подпись посетителя» › «Показать секрет».

Храните секрет на сервере сайта, в переменной окружения, например TOLKLY_IDENTITY_SECRET. Никогда не кладите его в код для браузера или в страницу: с ним можно войти под любым вашим клиентом.

Подпись на вашем сервере

Node.js:

JavaScript
// npm install jsonwebtoken
import jwt from 'jsonwebtoken'

const token = jwt.sign(
  {
    sub: String(user.id),
    name: user.name,
    email: user.email,
  },
  process.env.TOLKLY_IDENTITY_SECRET,
  { algorithm: 'HS256', expiresIn: '12h' },
)

PHP:

PHP
// composer require firebase/php-jwt
use Firebase\JWT\JWT;

$token = JWT::encode([
  'sub' => (string) $user->id,
  'name' => $user->name,
  'email' => $user->email,
  'exp' => time() + 12 * 3600,
], getenv('TOLKLY_IDENTITY_SECRET'), 'HS256');

Python:

Python
# pip install pyjwt
import os, time, jwt

token = jwt.encode({
    "sub": str(user.id),
    "name": user.name,
    "email": user.email,
    "exp": int(time.time()) + 12 * 3600,
}, os.environ["TOLKLY_IDENTITY_SECRET"], algorithm="HS256")

Добавьте fields рядом с остальными полями, например fields: { vip: user.vip }.

Передайте токен чату

Если страница собирается для вошедшего пользователя, поставьте токен на тег:

HTML
<tolkly-chat endpoint="https://api.tolkly.io" project="your-project"
  data-identity="<token>"></tolkly-chat>

Если пользователь вошёл без перезагрузки страницы, передайте токен из скрипта:

JavaScript
await customElements.whenDefined('tolkly-chat')
document.querySelector('tolkly-chat').identify(token)

Элемент также следит за data-identity: если поменять атрибут, чат заново определит посетителя.

При выходе вызовите reset() и перестаньте выводить data-identity. Чат забудет посетителя и разговор, сохранённый в этом браузере, и следующий человек за этим компьютером начнёт заново. Если в браузере лежит разговор другого подписанного посетителя, сервер тоже выдаст новый разговор.

Поручить ИИ-агенту

У владельцев и администраторов есть кнопка «Поручить ИИ-агенту»: «Установка» › «Дополнительно», блок «Подпись посетителя». Она даёт промпт ниже, с уже подставленным проектом, для агента, который правит сайт (Claude Code, Cursor). По этому промпту агент:

  • подписывает токен на сервере секретом из TOLKLY_IDENTITY_SECRET;
  • передаёт токен через data-identity или identify(token);
  • вызывает reset() при выходе;
  • проверяет результат в карточке посетителя в инбоксе.

Промпт называет переменную окружения, но не сам секрет. Здесь вместо идентификатора проекта стоит your-project. Скопировать промпт: «Открыть в…» › «Промпт для ИИ-агента».

Добавь подпись посетителя в чат поддержки Tolkly на этом сайте, чтобы операторы видели, какой клиент пишет.

Проект: your-project
Endpoint виджета: https://api.tolkly.io
Секрет: переменная окружения TOLKLY_IDENTITY_SECRET на сервере сайта. Владелец копирует его в Tolkly: «Установка» › «Дополнительно» › «Подпись посетителя» › «Показать секрет».

1. Прочитай https://tolkly.io/docs/en/identity.md. Если страница не открывается, хватит этого промпта.
2. Найди, где сервер сайта знает вошедшего пользователя (сессия, middleware авторизации), и шаблон, который выводит тег <tolkly-chat>. Если тега <tolkly-chat> на сайте ещё нет, остановись и скажи мне: сначала ставится сам чат.
3. На сервере подпиши для вошедшего пользователя JWT с алгоритмом HS256 секретом из TOLKLY_IDENTITY_SECRET, обычной для платформы библиотекой JWT. Никогда не подписывай в коде страницы и не передавай секрет в страницу. Если переменная не задана, остановись и попроси меня её задать; секрет в репозиторий не записывай.
4. Поля: "sub" — id пользователя строкой (обязательно, до 200 символов); "name" — имя, которое видят операторы (до 120); "email" и "phone", если они есть на сайте; "exp" — срок действия в секундах от начала эпохи, например на 12 часов вперёд. Дополнительные данные — в "fields": {…}, только ключи, которые объявил проект (они перечислены в том же блоке под «Поля, которые может передать сайт»); всё остальное отбрасывается. Содержимое токена видно в странице: передавай только то, что можно видеть посетителю.
5. Передай токен чату. Когда страница выводится для вошедшего посетителя, поставь его на тег: data-identity="<token>". После входа без перезагрузки страницы вызови identify(token) у элемента: await customElements.whenDefined('tolkly-chat'); document.querySelector('tolkly-chat').identify(token). Анонимному посетителю data-identity не выводи.
6. При выходе вызови document.querySelector('tolkly-chat').reset() и перестань выводить data-identity, чтобы следующий человек за этим компьютером начал с чистого листа.
7. Проверь в браузере: войди на сайте, открой чат и напиши сообщение. В инбоксе Tolkly, во вкладке «Все», в карточке посетителя «Аккаунт на сайте» виден id пользователя с отметкой «Проверено». В консоли браузера нет строки "tolkly: the identity token was refused (…)"; если она есть, слово в скобках говорит почему (malformed, algorithm, signature, expired). Потом выйди и снова открой чат: он анонимный, с новым разговором. Потом перечисли изменённые файлы.

Без подписи

identify({ id, name, email, phone, fields }) называет посетителя без токена. Операторы видят эти данные с пометкой «Не проверено». Они сохраняются только в этом разговоре. Они не попадают в историю между устройствами и не забирают разговор подписанного посетителя.

Отклонённый токен

Чат работает как анонимный и пишет причину в консоль браузера:

tolkly: the identity token was refused (signature)
КодПочему
malformedНе три части base64url с JSON, нет sub или он длиннее 200 символов, exp не число, или токен длиннее 8192 символов.
algorithmВ заголовке другой алгоритм, не HS256.
signatureПодписан другим секретом: старым или от другого проекта.
expiredСрок exp истёк, даже с учётом допустимого расхождения часов.

Смена секрета

Нажмите «Выпустить новый секрет» в приложении (только для владельцев и администраторов). Старый секрет сразу перестаёт работать. Подписанные им токены отклоняются с кодом signature, пока ваш сервер не начнёт подписывать новым. Поэтому меняйте секрет вместе с выкладкой.