Δ Delta Key

Протокол TwinCard Bots, версия 1

Как подключить чат-бота сторонней компании к цифровому сотруднику на бизнес-странице TwinCard. Модель — как у сервисов вида «адрес бота + токен»: TwinCard — канал, ваш бот — мозг.

Как это устроено

1. Сообщение от TwinCard

POST на ваш адрес бота, только https://. Заголовки:

ЗаголовокЗначение
Content-Typeapplication/json
AuthorizationBearer <ваш токен> — если вы выдали токен
X-AI2-Timestampвремя отправки, секунды Unix
X-AI2-Signaturesha256= + hex(HMAC-SHA256(timestamp + "\n" + тело запроса, секрет))
{
  "event": "message",                 // "test" — кнопка «Проверить связь» в TwinCard
  "version": 1,
  "bot":          { "id": "1c0f…-guid сотрудника", "name": "Анна" },
  "conversation": { "id": "g1234", "channel": "web" },   // web | telegram | app | voice | test
  "visitor":      { "id": "обезличенный sha256", "name": null, "lang": "ru" },
  "message":      { "id": "98765", "text": "Здравствуйте, сколько стоит стрижка?", "sent_at": "2026-10-03T17:00:00Z" },
  "history": [ { "role": "visitor", "text": "…" }, { "role": "bot", "text": "…" }, { "role": "operator", "text": "…" } ],
  "reply_url": "https://twincard.ru/api/public/bots/<guid сотрудника>/reply"
}

2. Ваш ответ

Сразу — в ответе на запрос (до 10 секунд)

HTTP/1.1 200 OK
Content-Type: application/json

{ "reply": "Здравствуйте! Стрижка — от 1 500 ₽. Записать вас?" }

Подходят также {"text": "…"} и {"messages": [{"text": "…"}, {"text": "…"}]} (несколько сообщений склеиваются в одно). До 8 000 символов. Только бот, отвечающий сразу, может говорить в голосовом звонке — текст читает голос TwinCard.

Позже — отдельным запросом

Ответьте на сообщение TwinCard кодом 200 или 202 без поля reply (например, {"accepted": true}), а ответ пришлите на reply_url:

POST https://twincard.ru/api/public/bots/<guid сотрудника>/reply
Content-Type: application/json
X-AI2-Timestamp: 1790000000
X-AI2-Signature: sha256=<hex(HMAC-SHA256(timestamp + "\n" + тело, секрет))>

{ "conversation_id": "g1234", "text": "Записала вас на 18:00. Ждём!" }
Ответ TwinCardЗначение
200 {"success": true, "data": {"delivered": true}}ответ доставлен посетителю
200 … "delivered": falseразговор сейчас ведёт оператор компании — ответ не показан
401 stale / bad_signatureневерная подпись или время
404 conversation_not_foundразговор не принадлежит этому сотруднику
422 bad_payloadнет текста или идентификатора разговора

3. Ошибки и недоступность

4. Проверка подписи — пример

// PHP
$expected = 'sha256=' . hash_hmac('sha256', $_SERVER['HTTP_X_AI2_TIMESTAMP'] . "\n" . file_get_contents('php://input'), $secret);
$ok = hash_equals($expected, $_SERVER['HTTP_X_AI2_SIGNATURE']);

// Node.js
const sig = 'sha256=' + crypto.createHmac('sha256', secret).update(ts + '\n' + rawBody).digest('hex');

# Python
sig = 'sha256=' + hmac.new(secret.encode(), (ts + '\n').encode() + raw_body, hashlib.sha256).hexdigest()

5. Что дальше (следующие версии)

Delta Key — тестовый стенд: здесь можно завести бота и проверить весь путь до продакшена.