Webhooks IZI: подписка на события
Webhooks IZI: подписка на события
Заголовок раздела «Webhooks IZI: подписка на события»Webhooks — способ получать события из IZI в реальном времени без постоянного опроса API. Сессия началась, баланс пополнен, клиент зарегистрирован — IZI сам отправит POST на ваш endpoint.
Это удобнее polling’а для любой интеграции, которой нужна реакция на события: синхронизация с кассой, уведомления в мессенджер, начисление бонусов во внешней системе.
Шаг 1 — Создать webhook
Заголовок раздела «Шаг 1 — Создать webhook»mutation CreateWebhook($input: CreateWebhookInput!) { createWebhook(input: $input) { id url events secret isActive }}{ "input": { "url": "https://your-service.example.com/izi/events", "events": [ "SESSION_STARTED", "SESSION_ENDED", "BALANCE_TOPPED_UP" ], "clubId": "club_abc123" }}В ответе получите secret — сохраните его. Он нужен для верификации подписи. Повторно получить нельзя.
Список событий
Заголовок раздела «Список событий»| Событие | Когда срабатывает |
|---|---|
SESSION_STARTED | Начало игровой сессии на устройстве |
SESSION_ENDED | Завершение сессии |
SESSION_PAUSED | Пауза сессии |
BALANCE_TOPPED_UP | Пополнение денежного баланса клиента |
BONUS_CREDITED | Начисление бонусов |
TARIFF_PURCHASED | Покупка тарифа клиентом |
CLIENT_REGISTERED | Регистрация нового клиента |
DEVICE_STATUS_CHANGED | Изменение статуса устройства (online/offline) |
SHIFT_OPENED | Открытие смены администратором |
SHIFT_CLOSED | Закрытие смены |
ORDER_CREATED | Новый заказ в баре |
PAYMENT_RECEIVED | Входящий платёж |
Актуальный полный список через introspection:
{ __type(name: "WebhookEventType") { enumValues { name description } }}Шаг 2 — Структура payload
Заголовок раздела «Шаг 2 — Структура payload»Каждое событие приходит как POST с JSON-телом:
{ "id": "evt_01HZ3K...", "type": "SESSION_ENDED", "timestamp": "2026-05-30T14:32:00Z", "clubId": "club_abc123", "data": { "sessionId": "sess_xyz789", "deviceId": "device_001", "clientId": "client_456", "duration": 3600, "cost": 150, "endReason": "MANUAL" }}Поля id, type, timestamp, clubId — всегда присутствуют. Содержимое data зависит от типа события.
Шаг 3 — Верифицировать подпись
Заголовок раздела «Шаг 3 — Верифицировать подпись»Каждый запрос от IZI содержит заголовок X-IZI-Signature — HMAC-SHA256 от тела запроса с вашим секретом.
const crypto = require('crypto');
function verifySignature(payload, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(payload, 'utf8') .digest('hex');
// Сравнение безопасное к timing-атакам return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) );}
// В вашем обработчикеapp.post('/izi/events', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-izi-signature'];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); }
const event = JSON.parse(req.body); processEvent(event);
res.status(200).send('OK');});Важно: используйте express.raw() или аналог — нужно именно сырое тело для корректного подсчёта подписи. Если парсите JSON до проверки — подпись не сойдётся.
Идемпотентность
Заголовок раздела «Идемпотентность»IZI доставляет события с гарантией “хотя бы один раз”. Одно событие может прийти дважды при сетевых сбоях. Защититесь от дублей:
const processedEvents = new Set(); // в проде — Redis или БД
async function processEvent(event) { if (processedEvents.has(event.id)) { console.log(`Skipping duplicate event: ${event.id}`); return; }
await handleEvent(event); // ваша бизнес-логика processedEvents.add(event.id);}Используйте поле event.id как ключ идемпотентности.
Политика повторных попыток
Заголовок раздела «Политика повторных попыток»Если ваш endpoint не ответил 200 OK в течение 5 секунд, IZI повторит доставку:
| Попытка | Задержка |
|---|---|
| 2 | 30 секунд |
| 3 | 5 минут |
| 4 | 30 минут |
| 5 | 2 часа |
| 6 | 24 часа |
После 6 неудачных попыток webhook переходит в статус FAILED. Для реактивации:
mutation ReactivateWebhook($id: ID!) { updateWebhook(id: $id, input: { isActive: true }) { id isActive }}Управление webhook’ами
Заголовок раздела «Управление webhook’ами»Список всех webhook’ов организации:
query ListWebhooks { webhooks { id url events isActive lastDeliveredAt failureCount }}Удаление:
mutation DeleteWebhook($id: ID!) { deleteWebhook(id: $id) { success }}Тестирование локально
Заголовок раздела «Тестирование локально»# Установите ngrokbrew install ngrok
# Откройте туннельngrok http 3000
# Используйте полученный URL при создании webhook# https://abc123.ngrok.io/izi/eventsСвязанные страницы
Заголовок раздела «Связанные страницы»- IZI API: обзор — общая архитектура
- Авторизация и токены — токен для создания webhook
- Коды ошибок API — ошибки при регистрации webhook
- Примеры SDK — готовые обработчики webhook на JS/Python
См. также
Заголовок раздела «См. также»Частые вопросы
Какие события поддерживают webhooks?
SESSION_STARTED, SESSION_ENDED, BALANCE_TOPPED_UP, TARIFF_PURCHASED, DEVICE_STATUS_CHANGED, CLIENT_REGISTERED — и ещё около 15 типов событий. Полный список через introspection: __type(name: WebhookEventType).
Что делает IZI если endpoint не отвечает?
IZI повторяет доставку с экспоненциальной задержкой: 30 сек, 5 мин, 30 мин, 2 часа, 24 часа. После 5 неудачных попыток webhook помечается как failed и требует ручной активации.
Можно ли подписаться на события конкретного клуба?
Да. При создании webhook укажите clubId — тогда события будут только по этому клубу. Без clubId приходят события по всем клубам организации.
Как протестировать webhook локально?
Используйте ngrok или cloudflare tunnel для временного публичного URL. Потом замените на production endpoint.