Что это
Webhooks — механизм уведомления вашей системы о событиях в кабинете в реальном времени. Вместо того чтобы периодически опрашивать API, вы регистрируете URL — и MCM шлёт POST-запрос на него при каждом событии.
Подписка
Через UI: /integrations → раздел «Webhooks» → форма «URL + события» → «+».
Через API:
POST /api/v1/webhooks
Authorization: Bearer mcm_...
Content-Type: application/json
{
"url": "https://crm.example.com/mcm-hook",
"events": ["call.end", "callback.requested"]
}
Ответ:
{
"ok": true,
"id": 7,
"secret": "1f2c3d...",
"note": "Сохраните secret — больше он не будет показан."
}
Этот secret используется для проверки подписи каждого пуша.
Формат пуша
POST https://crm.example.com/mcm-hook
Content-Type: application/json
X-MCM-Event: call.end
X-MCM-Signature: sha256=<hex>
User-Agent: mcm-webhook/1.0
{
"event": "call.end",
"tenant_id": "uuid",
"data": { ... },
"ts": "2026-05-01T22:30:00+00:00"
}
Проверка подписи
Python:
import hmac, hashlib
def verify(secret, body, header_signature):
expected = 'sha256=' + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header_signature)
# в обработчике:
sig = request.headers['X-MCM-Signature']
if not verify(SECRET, request.body, sig):
return Response(403)
PHP:
function verifyMcmWebhook(string $secret, string $body, string $sig): bool {
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
return hash_equals($expected, $sig);
}
Поддерживаемые события
call.start |
Начало звонка |
call.end |
Завершение звонка |
call.answered |
Ответ на звонок |
call.missed |
Пропущенный звонок |
chat.new |
Новый чат с сайта |
chat.message |
Новое сообщение в чате |
callback.requested |
Заказ обратного звонка из коллтрекинга/виджета |
transcript.ready |
Транскрипция готова |
* |
Все события |
Retry policy
Если ваш сервер вернул статус не 2xx или не ответил — MCM повторяет доставку:
- Попытка 1 — сразу
- Попытка 2 — через 60 секунд
- Попытка 3 — через 5 минут
- Попытка 4 — через 30 минут
- Попытка 5 — через 2 часа
После 5 неудачных попыток событие помечается delivered_at = now() с last_error = "GIVE UP" и больше не отправляется. Статус последней попытки виден в /integrations.
Идемпотентность
Каждое событие имеет уникальный data.linkedid (для звонков) или data.session_id (для чатов). Используйте это поле как идемпотентность-ключ — при повторной доставке (retry) одного и того же события данные те же.
Типичные интеграции
- amoCRM/Bitrix24 — подпишитесь на
call.end,callback.requested. Поcall.endсоздавайте сделку/задачу; поcallback.requested— лид. - Slack/Telegram — на
call.missedшлите сообщение оператору с номером и временем. - Google Sheets / BI — на
call.endдобавляйте строку в таблицу для аналитики.