Skip to content

Вебхуки

На цій сторінці описано два напрямки: події, які ми надсилаємо вам, і сигнал, яким ваша система будить агента.

У них різні схеми підпису

Це найлегше переплутати. Вихідні вебхуки підписують timestamp + "." + тіло. Вхідний сигнал тригера підписує тільки тіло.

Вихідні: події операторської роботи

Ми надсилаємо POST на вашу адресу при трьох подіях. Адреса вебхука задається в конфігурації агента.

ПодіяКолиЩо всередині
escalatedрозмову передано людиніtranscript — недавній контекст
visitor_messageвідвідувач написав у переданій розмовіtext — його репліка
resolvedзвернення закрито
json
{
  "event": "escalated",
  "bot_id": "bot_7f3a1c",
  "session_id": "3f6c1b9e-7f42-4d2a-9a6f-0d5b1f0b21c7",
  "transcript": "Клієнт: Замовлення №4417 досі не приїхало\nБот: За даними перевізника посилка в дорозі…\nКлієнт: Мені це вже казали тиждень тому. Покличте людину.",
  "at": 1753600000123
}

session_id — ключ до всього подальшого: саме з ним працює операторська частина API.

Подія resolved приходить і тоді, коли звернення закрили ви самі через API. Це навмисно: так дві операторські системи — кабінет і ваша — лишаються синхронними.

Підпис

Кожна доставка підписана двома заголовками:

X-YouSelfBot-Timestamp: 1753600000
X-YouSelfBot-Signature: sha256=<hex>

Підпис — це HMAC-SHA256(секрет, "<timestamp>.<сире тіло>") у hex. Секрет агента — у його конфігурації (handoff_webhook_secret), починається з whsec_.

Часова мітка входить у підпис

Підписаний рядок — timestamp + "." + body. Це дозволяє відхиляти старі доставки: перехоплений запит не можна відтворити пізніше, навіть якщо підпис досі математично вірний.

python
import hashlib, hmac, time

def verify(raw_body: bytes, headers, secret: str, tolerance: int = 300) -> bool:
    ts = headers.get("X-YouSelfBot-Timestamp", "")
    got = headers.get("X-YouSelfBot-Signature", "").removeprefix("sha256=")
    if not ts.isdigit() or abs(time.time() - int(ts)) > tolerance:
        return False                       # застаріла доставка
    mac = hmac.new(secret.encode(), ts.encode() + b"." + raw_body, hashlib.sha256)
    return hmac.compare_digest(mac.hexdigest(), got)
javascript
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verify(rawBody, headers, secret, tolerance = 300) {
  const ts = headers['x-youselfbot-timestamp'] ?? '';
  const got = (headers['x-youselfbot-signature'] ?? '').replace(/^sha256=/, '');
  if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > tolerance) return false;

  const want = createHmac('sha256', secret)
    .update(ts + '.')
    .update(rawBody)
    .digest('hex');

  const a = Buffer.from(want);
  const b = Buffer.from(got);
  return a.length === b.length && timingSafeEqual(a, b);
}

Три правила, які легко порушити:

  1. Рахуйте HMAC над сирим тілом, до JSON-парсингу. Переформатований JSON дасть інший підпис.
  2. Порівнюйте у сталий час (compare_digest, timingSafeEqual), а не через ==.
  3. Відхиляйте старі доставки — кілька хвилин допуску достатньо.

Повтори

Невдалу доставку ми повторюємо тричі — через 1, 5 і 25 секунд. Повторюються лише 5xx і мережеві помилки: 4xx — це ваша система каже, що запит неправильний, і повторювати його немає сенсу.

Звідси два наслідки:

  • Обробник має бути ідемпотентним — та сама подія може прийти двічі.
  • Відповідайте 200 одразу, а роботу робіть після. На доставку відводиться 5 секунд.

Адреса вебхука має бути публічною: запити у приватні мережі ми не робимо навмисно.

Вхідний сигнал тригера

Зворотний напрямок: ваша система будить агента, коли у вас щось сталося.

Тригер створюється в кабінеті — агент → ТригериДодати тригерЗа сигналом ззовні. Одразу після створення кабінет один раз покаже посилання й секрет. Див. Щоб працював без вас.

POST https://api.youselfbot.com/v1/hooks/{tid}

Підпис

Автентифікація — HMAC-підпис тіла, а не ключ у заголовку:

X-Hook-Signature: sha256=<hex HMAC-SHA256(секрет, тіло)>

Підписується тільки тіло, без часової мітки — на відміну від вихідних вебхуків вище.

bash
BODY='{"order_id":4417,"status":"delayed"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$HOOK_SECRET" -hex | awk '{print $2}')

curl -sS -X POST "https://api.youselfbot.com/v1/hooks/trg_01j9x2h7q0" \
  -H "X-Hook-Signature: sha256=$SIG" \
  -H "Content-Type: application/json" \
  -d "$BODY"
python
import hashlib, hmac, json, requests

body = json.dumps({"order_id": 4417, "status": "delayed"}).encode()
sig = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()

requests.post(
    "https://api.youselfbot.com/v1/hooks/trg_01j9x2h7q0",
    data=body,
    headers={"Content-Type": "application/json", "X-Hook-Signature": "sha256=" + sig},
)

Найчастіша помилка — порахувати HMAC над переформатованим JSON. Підписуйте ті самі байти, які надсилаєте.

Сам ідентифікатор тригера в адресі непередбачуваний, але секретом не вважається: адреса осідає в чужих конфігураціях і логах. Тому без валідного підпису — завжди 401.

Дві поведінки відповіді

Задаються в кабінеті, у формі тригера.

«Підтвердити одразу»202 Accepted одразу, робота йде у фоні:

json
{ "status": "accepted" }

«Дочекатися відповіді агента» — з'єднання тримається до кінця роботи:

json
{
  "run_id": "run_01j9x2m4p8",
  "status": "done",
  "answer": "Клієнта попереджено, доставку перенесено на завтра."
}

Перший варіант правильний майже завжди: чужі системи часто мають короткий таймаут, а робота агента може тривати хвилини. Другий беріть, лише коли відповідь потрібна викликачу негайно, — і закладайте власний таймаут на своєму боці.

Якщо синхронний запуск упав — 502 з run_id, щоб знайти його в журналі Запуски.

Що бачить агент

Вхід запуску — це Задача запуску з тригера плюс сире тіло сигналу:

Обробі подію із CRM і, якщо потрібно, напиши мені.

Подія (тіло вебхука):
{"order_id":4417,"status":"delayed"}

Тобто в тригері ви пишете, що робити, а сигнал приносить, з чим.

Обмеження

Розмір тіладо 256 КіБ
Вимкнений тригер409
Невідомий або видалений тригер404
Невірний підпис401

Дедуплікації немає

Повторна доставка тієї самої події зробить другий запуск. Якщо ваше джерело може доставити подію двічі, тримайте ознаку обробленого в позначках агента — розділ Стан, див. Позначки між запусками.

П'ять невдалих запусків поспіль ставлять тригер на паузу

Це захист від зламаної задачі, яка витрачала б кредити цілу ніч. Тригер треба буде ввімкнути вручну — див. Тригер на паузі.

Далі

Для розробника — виклики розмови, операторської роботи та знань.

Документація платформи YouSelfBot