Вебхуки
Mison сам сообщает вашему серверу о событиях: кассир посадил гостя по брони, закрыл счёт, гость не пришёл, заведение отклонило заявку, кто-то занял стол. Вам не нужно опрашивать API — достаточно принимать POST-запросы.
Сейчас вебхуки есть у брони столов.
Подключение
Адрес вебхука указывает заведение в кабинете: Интеграции → API-ключи → меню ключа → Вебхук. Там же:
- события — какие присылать. Ничего не отмечено — приходят все;
- секрет подписи — передайте его себе на сервер, им проверяется подпись;
- проверить — Mison сразу отправит событие
pingи покажет ответ вашего сервера; - последние отправки — журнал: что ушло, что не дошло, с кодом ответа и ошибкой. Недоставленное можно отправить ещё раз кнопкой.
Вебхук работает, пока у ключа включено «Бронирование столов» и не истёк срок ключа.
Запрос
POST {ваш адрес}
Content-Type: application/json
X-Mison-Event: reservation.status_changed
X-Mison-Event-Id: 6f1c2d5e-8a7b-4c3d-9e0f-1a2b3c4d5e6f
X-Mison-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
{
"event_id": "6f1c2d5e-8a7b-4c3d-9e0f-1a2b3c4d5e6f",
"event": "reservation.status_changed",
"occurred_at": "2026-10-25T19:04:11+05:00",
"data": {
"id": "72179267-7a2c-47a7-a4ae-8d1b48b2f977",
"external_id": "booking-58123",
"status": "opened"
}
}
В data для событий reservation.* — бронь целиком, в том же виде, что отдаёт GET /reservations/{id} (выше показана сокращённо).
Ответьте любым кодом 2xx в течение 5 секунд — событие доставлено. Тело ответа не читается.
События
| Событие | Когда | data |
|---|---|---|
reservation.created | Создана ваша бронь | Бронь |
reservation.updated | Изменена ваша бронь: перенос, стол, гости, итог депозита | Бронь |
reservation.status_changed | Сменился статус вашей брони: подтверждена, гость сел, счёт закрыт, не пришёл, отменена, отклонена | Бронь |
occupancy.changed | Изменилась чужая бронь в заведении — касса, колл-центр, другой сервис | Занятость стола, без гостя |
ping | Проверка из кабинета | { "message": "…" } |
occupancy.changed нужен, чтобы держать актуальной свою картину свободных столов:
{
"event": "occupancy.changed",
"data": {
"point_id": "c91fdd54-a539-44ab-8a8f-103838d31388",
"table_id": 11238,
"date": "2026-10-25",
"start_time": "18:00",
"end_time": "20:00",
"guests": 2,
"is_holding": true
}
}
is_holding: false — стол больше не держится этой бронью (её отменили, закрыли или гость не пришёл). table_id: null — бронь на заведение без стола.
Проверка подписи
X-Mison-Signature — HMAC-SHA256 сырого тела запроса секретом подписи, в hex, с префиксом sha256=. Считайте подпись по телу как оно пришло, до разбора JSON:
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_MISON_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
const crypto = require('crypto')
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.get('X-Mison-Signature') || ''))
Секрет можно перевыпустить в кабинете — старый перестаёт работать сразу.
Повторы и порядок
Не ответили 2xx (ошибка, таймаут, сервер недоступен) — Mison повторит через 1, 5, 30 минут, 2 и 6 часов. После шестой неудачи событие помечается недоставленным; его можно отправить снова из кабинета, а пропущенное догнать лентой изменений.
Поэтому:
- одно событие может прийти дважды — дедуплицируйте по
event_id; - события могут прийти не по порядку (повтор старого после нового) — сравнивайте
data.updated_atброни и не откатывайте свежее состояние старым.