Подписка на события
Конструктор сам сообщает вашему сервису о том, что произошло в боте: появился подписчик, прошла оплата, клиент перешёл на другой этап. Опрашивать API в цикле не нужно.
Права: hooks:read для чтения, hooks:write для создания и удаления подписок. Подписки видно и в кабинете, на странице настроек аккаунта.
Как это работает
- Вы создаёте подписку: адрес своего обработчика и список событий.
- Когда событие происходит, конструктор ставит доставку в очередь и отправляет на ваш адрес
POSTс телом JSON — обычно в ту же секунду. - Ваш обработчик отвечает любым кодом
2xx— доставка считается успешной. - Если не ответил или ответил ошибкой, попытка повторяется пять раз: сразу, через 5 секунд, 30 секунд, 5 минут и полчаса. Всего у вашего сервера есть около 35 минут, чтобы прийти в себя.
- Двадцать неудачных доставок подряд выключают подписку — мёртвый адрес не должен вечно занимать очередь. Включить её обратно можно в кабинете или методом
/hook/edit.
Что происходит, если перезапустить конструктор
Ничего не теряется. Событие сначала становится заданием в очереди и только потом уходит: если приложение перезапустили посреди паузы между попытками, задание остаётся в базе, и его подберёт фоновая проверка. Доставленное задание удаляется сразу — след остаётся в журнале доставок.
Потолок одновременных доставок
К одной подписке конструктор не отправляет больше четырёх запросов одновременно, а на весь процесс их не больше двадцати. Так рассылка на тысячу подписчиков при подписке на message.out не превратится в тысячу параллельных запросов к вашему серверу.
Обратная сторона: порядок доставки не гарантирован. Два события, случившиеся подряд, могут прийти в обратном порядке. Если порядок важен, ориентируйтесь на поле at внутри тела.
Какие бывают события
| Событие | Когда приходит |
|---|---|
subscriber.new | в боте появился новый подписчик |
subscriber.blocked | подписчик заблокировал бота или отписался |
subscriber.unblocked | подписчик вернулся |
subscriber.tag | подписчику навесили тег |
subscriber.stage | подписчик перешёл на другой этап воронки |
message.in | подписчик написал боту |
message.out | бот отправил сообщение подписчику |
block.reached | подписчик дошёл до блока |
payment.success | оплата прошла |
lead.new | заявка отправлена сотруднику |
scenario.error | сценарий действий завершился ошибкой |
Актуальный список всегда можно получить методом GET /hook/events.
message.* и block.reached — самые частыеНа боте с тысячей подписчиков эти события идут потоком. Подписывайтесь на них, только если действительно обрабатываете каждое; для большинства задач хватает subscriber.new, payment.success и subscriber.stage.
Создать подписку
POST /hook/create
curl -X POST https://api.quescha.com/api/hook/create \
-H "Authorization: ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
-d '{
"name": "Наш CRM",
"url": "https://example.com/quescha/hook",
"events": ["subscriber.new", "payment.success"]
}'
| Поле | Обязательный | Описание |
|---|---|---|
url | Да | куда слать; только http:// или https:// |
events | Нет | массив событий; пусто — все |
name | Нет | название для кабинета |
bots | Нет | массив BotID: события только этих ботов |
secret | Нет | свой секрет подписи; по умолчанию генерируется |
В ответе приходит secret — сохраните его, им проверяется подпись.
Что приходит
POST /quescha/hook HTTP/1.1
Content-Type: application/json
X-Quescha-Event: payment.success
X-Quescha-Delivery: fJk29dhSl2…
X-Quescha-Attempt: 1
X-Quescha-Signature: 9f2c…
{
"event": "payment.success",
"delivery": "fJk29dhSl2…",
"at": "2026-08-28T11:42:07.113Z",
"data": {
"payment": 91024,
"system": "yookassa",
"sum": "3500",
"currency": "RUB",
"description": "Заказ A-1024",
"clientid": "987654321",
"payloads": [{ "name": "order", "data": "A-1024" }]
}
}
У событий о подписчике в data приходят botid, clientid, messenger, name, username и внутренний номер карточки subscriber. У subscriber.stage добавляется stage, у subscriber.tag — tag, у block.reached — block, blockname и blocknum, у message.in и message.out — text.
Проверка подписи
Тело подписывается HMAC-SHA256 на секрете подписки. Считайте подпись от сырого тела запроса — до разбора JSON.
// Node.js, express
const crypto = require('crypto')
app.post('/quescha/hook', express.raw({ type: 'application/json' }), (req, res) => {
const mine = crypto.createHmac('sha256', SECRET).update(req.body).digest('hex')
if (mine !== req.headers['x-quescha-signature']) return res.status(403).end()
const event = JSON.parse(req.body.toString('utf8'))
// …обрабатываем
res.send('ok')
})
# Python, Flask
import hmac, hashlib
@app.post('/quescha/hook')
def hook():
mine = hmac.new(SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(mine, request.headers.get('X-Quescha-Signature', '')):
return '', 403
event = request.get_json()
return 'ok'
Если ваш сервер ответил медленно или упал после обработки, доставка повторится. Считайте delivery идентификатором и пропускайте уже обработанные: так вы не создадите вторую сделку по одной оплате.
Заголовок X-Quescha-Attempt показывает номер попытки — по нему видно, что это повтор. Тело и подпись у всех попыток одной доставки совпадают дословно.
Проверить, что всё дошло
POST /hook/test с id подписки шлёт пробное событие test тем же кодом и с той же подписью:
{ "ok": true, "status": 200, "ms": 84, "error": null }
GET|POST /hook/log — журнал доставок: что отправляли, чем ответили и с какой попытки получилось. Фильтры: id, event, failed.
Остальные методы
GET|POST /hook/list — подписки аккаунта.
POST /hook/edit — поменять адрес, события или включить выключенную подписку (active: true заодно обнуляет счётчик неудач).
POST /hook/delete — удалить подписку.