Получать события Slen
Что несёт доставка вебхука, как проверить её подпись, когда её отправляют снова и о чём сообщает каждое семейство событий.
6 мин чтения
Вебхук отправляет события Slen на адрес вашего сервиса по мере того, как они происходят: взят холд, бюджет почти потрачен, вызов закончился, выполнение ждёт решения. Эта статья — о том, что приходит на этот адрес и как это читать. Вебхуки добавляют и меняют в консоли — статья Вебхуки показывает как.
Что несёт доставка
Доставка — это POST с телом JSON и заголовком Content-Type: application/json. Тело — это событие.
{
"id": "74443412671954944",
"type": "operation.uncertain",
"created_at": "2026-10-02T09:13:04+00:00",
"data": {
"reservation_id": "74442097331195904",
"project_id": "74438200973594624",
"operation_code": "generate_email",
"external_user_id": "user_8421",
"model": "gpt-4o-mini",
"reason": "operation_uncertain",
"hold_expires_at": "2026-10-02T09:27:04+00:00"
}
}idназывает событие. Каждый вебхук, который слышит событие, получает тот жеid.type— имя события, аdataнесёт то, о чём событие: id, суммы, статусы. Он никогда не несёт промпт или ответ модели.created_at— момент, когда событие произошло, а не момент доставки.
Проверьте подпись
Каждая доставка подписана секретом вебхука, который показывают один раз при создании вебхука. Подпись идёт в заголовке доставки рядом с типом её тела:
POST /webhooks/slen HTTP/1.1
Content-Type: application/json
Slen-Signature: t=1759396384,v1=5f0c8e2a…t — время подписи в секундах с 1970 года, а v1 — подпись.
1. Соберите подписанный текст
Соедините значение t, точку и тело точно в том виде, в каком оно пришло, байт в байт. Не разбирайте тело и не записывайте его заново перед этим.
2. Вычислите подпись
Вычислите HMAC-SHA256 этого текста с секретом в роли ключа, записанный строчными шестнадцатеричными цифрами.
printf '%s.%s' "$T" "$BODY" | openssl dgst -sha256 -hmac "$SECRET"3. Сравните
Сравните результат со значением v1 за постоянное время. Отклоните доставку, подпись которой отличается, и доставку, чьё t далеко от ваших часов, — это старая доставка, которую кто-то отправил снова.
Когда доставку отправляют снова
Ваш сервис отвечает
2xx, чтобы принять доставку. Отвечайте сразу, а работу делайте потом: Slen ждёт ответа 10 секунд, если сервис не настроен иначе.Ответ
400,401,403,404,410или422завершает доставку: её не отправляют снова.Любой другой ответ — перенаправление,
408,429,5xx— или отсутствие ответа вовремя считается сбоем, и доставку отправляют снова позже. Пауза начинается с 30 секунд и каждый раз удваивается, до часа. После 12 попыток от доставки отказываются. Это значения сервиса по умолчанию.Доставки уходят раз в минуту.
Одно и то же событие может прийти больше одного раза, а два события могут прийти не в своём порядке. Храните id каждого обработанного события и пропускайте то, которое уже видели.
Какие вебхуки слышат событие
Вебхук слышит события, на которые он подписан.
Вебхук одного проекта слышит события этого проекта.
Вебхук всех проектов слышит события каждого проекта организации и события, которые ни к какому проекту не относятся: каждое
connection.cooldown_startedи события подключения, бюджета или оповещения всей организации.Выключенный вебхук ничего не слышит. Доставка, которая уже его ждёт, всё равно отправляется.
События
Это события, которые отправляет Slen. Форма консоли предлагает часть из них; любое из них можно назвать через API.
| Объект | События |
|---|---|
reservation |
|
budget |
|
operation |
|
flow |
|
connection |
|
approval |
|
execution |
|
alert |
|
overrun |
|
customer |
|
ledger |
|
| Семейство | О чём сообщают его события |
|---|---|
reservation. | Холд взят, списан, освобождён или истёк; reservation.overrun — списание оказалось больше холда |
operation. | Вызов модели во флоу: холд, который он взял (operation.authorized), отказ бюджета, политики или блокировки клиента до вызова (operation.denied), начало вызова у провайдера и его конец — operation.completed, operation.failed или operation.uncertain |
budget. | Холд довёл использование бюджета до 50 % или 80 % его лимита (budget.threshold_reached) или до всего лимита (budget.exceeded) |
flow. | Опубликована версия флоу, или флоу откатили к более ранней версии |
execution. | Выполнение закончилось, с его status и error_code (execution.finished) |
approval. | Выполнение ждёт решения (approval.requested), и само решение: одобрено, отклонено или истекло (approval.decided) |
overrun. | Узел модели обнаружил, что вызов обойдётся дороже своего холда, и его политика перерасхода решила, что делать (overrun.decided) |
connection. | Подключение провайдера на время выведено из работы (connection.cooldown_started), или изменился его status (connection.health_changed) |
alert. | Оповещение открылось или разрешилось |
customer. | Доступные клиенту кредиты опустились ниже уровня, заданного для его счёта (customer.balance_low) |
ledger. | Slen начал пропускать вызовы без своего реестра (ledger.degraded), и это время кончилось (ledger.restored) |
Бюджет сообщает о каждом уровне не больше раза за окно — статья Бюджеты говорит когда. Оповещение сообщает о своём открытии и разрешении, а не о каждом обновлении — Оповещения.
События вызова модели
События семейств reservation. и operation., а также overrun.decided, приходят от вызовов модели во флоу. Конец вызова модели — одно из трёх событий, и каждое говорит о деньгах своё.
operation.completed— провайдер ответил.operation.failed— вызов не состоялся, и его холд вернули. Одно исключение: вызов, который провайдер выполнял в фоне и чей холд закрыло другое списание, пока он ждал, заканчивается сreason, равнымbackground_hold_expired. Ничего не возвращается, и провайдер всё ещё может выставить счёт за вызов.operation.uncertain— никто не знает, чем закончился вызов: потерян ответ узла модели, провайдер не ответил на начало фонового вызова, или о фоновом вызове больше нельзя было спросить. Холд остаётся доhold_expires_at, потому что провайдеру могли заплатить. Не повторяйте такой вызов, будто он не удался, — статья Когда исход неизвестен говорит, что делать.
Вызов, который провайдер выполняет в фоне, сообщает о своём начале, как любой вызов, а о своём конце — когда он наступает, одним из трёх событий.
Что читать дальше
Вебхуки — добавьте вебхук, выберите его события и сохраните его секрет.
Когда исход неизвестен — что делать с вызовом, который закончился со статусом
uncertain.Согласования — решите судьбу выполнения, о котором сообщило
approval.requested.Операции — запись вызова модели, о котором сообщают события семейства
operation..Вебхуки — проверьте подпись доставки и прочитайте её событие в SDK.
Собрано из openapi b070e1f, sdk contract 5cc7055, php ae4a53b, node 84bc62d