Перейти к основному содержимому

Подписка на события

Конструктор сам сообщает вашему сервису о том, что произошло в боте: появился подписчик, прошла оплата, клиент перешёл на другой этап. Опрашивать API в цикле не нужно.

Авторизация

Права: hooks:read для чтения, hooks:write для создания и удаления подписок. Подписки видно и в кабинете, на странице настроек аккаунта.


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

  1. Вы создаёте подписку: адрес своего обработчика и список событий.
  2. Когда событие происходит, конструктор ставит доставку в очередь и отправляет на ваш адрес POST с телом JSON — обычно в ту же секунду.
  3. Ваш обработчик отвечает любым кодом 2xx — доставка считается успешной.
  4. Если не ответил или ответил ошибкой, попытка повторяется пять раз: сразу, через 5 секунд, 30 секунд, 5 минут и полчаса. Всего у вашего сервера есть около 35 минут, чтобы прийти в себя.
  5. Двадцать неудачных доставок подряд выключают подписку — мёртвый адрес не должен вечно занимать очередь. Включить её обратно можно в кабинете или методом /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.tagtag, у block.reachedblock, blockname и blocknum, у message.in и message.outtext.


Проверка подписи

Тело подписывается 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 — удалить подписку.