Тема
Are you an LLM? You can read better optimized documentation at /api\webhooks.md for this page in Markdown format
Webhook-подписки
MaxBotStat умеет «зеркально» отправлять события на ваш HTTPS-эндпоинт. Это удобно, когда:
- у вас CRM, и нужно ловить новых контактов в реальном времени;
- вы хотите складывать сообщения в свою БД без поллинга REST API;
- нужна нотификация в Slack / Telegram-чат при определённом событии.
Поддерживаемые события
| Событие | Когда срабатывает |
|---|---|
message.created | новое входящее сообщение от пользователя |
message.outbound | бот отправил сообщение (через прокси, кабинет или REST) |
contact.created | контакт впервые появился в базе |
В будущем добавим funnel.step_passed, intent.matched, broadcast.completed.
Создать подписку
Только через приватный API кабинета
Управление подписками сейчас делается через приватный API (/api/me/webhooks) с JWT-токеном из кабинета. В публичном REST v1 этой ручки пока нет — мы намеренно не даём управлять webhook'ами через долгоживущие API-ключи.
Через UI кабинета: Настройки → Webhooks → Создать.
Через приватный API:
bash
curl -X POST "https://capybara.maxbotstat.ru/api/me/webhooks" \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/mbs-hook",
"events": ["message.created", "message.outbound", "contact.created"],
"bot_id": "5d4e3a2b-..."
}'Ответ:
json
{
"id": "67c8...",
"url": "https://yourapp.com/mbs-hook",
"events": ["message.created", "message.outbound", "contact.created"],
"active": true,
"created_at": "2026-04-30T12:00:00Z",
"secret": "whsec_AbCd...XyZ"
}Сохраните secret
secret отдаётся только при создании. Дальше через API его не получить. Он нужен для проверки подписи входящих webhook'ов.
bot_id опционален. Если указан — события приходят только от этого бота. Если не указан — со всех ваших ботов.
Формат входящего запроса
MaxBotStat шлёт POST на ваш url:
http
POST /mbs-hook HTTP/1.1
Host: yourapp.com
Content-Type: application/json
User-Agent: MaxBotStat-Webhook/1
X-Webhook-Event: message.created
X-Webhook-Signature: sha256=<hex>
{
"event": "message.created",
"delivered_at": "2026-04-30T15:23:01.123Z",
"subscription_id": "67c8...",
"data": {
"bot_id": "5d4e3a2b-...",
"message_id": "5d31...",
"direction": "in",
"external_user_id": "123456789",
"text": "Привет",
"created_at": "2026-04-30T15:23:01Z"
}
}Проверка подписи
Подпись считается как:
HMAC-SHA256(secret, raw_body) → hex → "sha256=" + hexjs
import crypto from 'crypto'
function verifyWebhook(rawBody, signature, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}
// Express
app.post('/mbs-hook', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifyWebhook(req.body, req.headers['x-webhook-signature'], process.env.MBS_SECRET)) {
return res.status(401).end()
}
const event = JSON.parse(req.body.toString())
// обработка...
res.json({ ok: true })
})python
import hmac, hashlib
def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)go
func verifyWebhook(rawBody []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(rawBody)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(signature))
}Тестовая доставка
В UI кабинета — кнопка Тест. Она шлёт событие test.ping:
json
{
"event": "test.ping",
"delivered_at": "...",
"subscription_id": "...",
"data": { "message": "Тестовая доставка от MaxBotStat", "timestamp": "..." }
}Через приватный API:
bash
curl -X POST "https://capybara.maxbotstat.ru/api/me/webhooks/<id>/test" \
-H "Authorization: Bearer <jwt>"Ретраи и таймаут
- Таймаут на ваш ответ — 10 секунд.
- Если ответ не 2xx — MaxBotStat не повторяет. История неудач видна через
/api/me/webhooks/<id>/deliveries. - Логи доставок хранятся 50 последних запросов на подписку.
Делайте обработку асинхронной
Не делайте тяжёлые операции в обработчике webhook'а. Положите событие в очередь (Redis, SQS, Kafka) и быстро ответьте 200.
Просмотр истории доставок
bash
curl "https://capybara.maxbotstat.ru/api/me/webhooks/<id>/deliveries" \
-H "Authorization: Bearer <jwt>"json
[
{ "event": "message.created", "status_code": 200, "error": null, "duration_ms": 87, "created_at": "..." },
{ "event": "message.created", "status_code": 502, "error": "fetch failed", "duration_ms": 30, "created_at": "..." }
]Лимиты
- Максимум 20 подписок на пользователя.
- Размер
events— любые из поддерживаемых, минимум один. - URL — только
http://илиhttps://, до 500 символов.