Pular para o conteúdo

IZI Webhooks: Subscribing to Events

Опубликовано: · IZI Team

Este conteúdo não está disponível em sua língua ainda.

Webhooks let you receive IZI events in real time without constantly polling the API. Session started, balance topped up, client registered — IZI sends a POST to your endpoint automatically.

This beats polling for any integration that needs to react to events: POS sync, messenger notifications, crediting bonuses in an external system.

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"
}
}

The response includes secret — save it immediately. It’s required for signature verification and cannot be retrieved again.

EventWhen It Fires
SESSION_STARTEDGaming session starts on a device
SESSION_ENDEDSession ends
SESSION_PAUSEDSession paused
BALANCE_TOPPED_UPClient cash balance topped up
BONUS_CREDITEDBonus points credited
TARIFF_PURCHASEDClient purchases a tariff
CLIENT_REGISTEREDNew client registered
DEVICE_STATUS_CHANGEDDevice goes online/offline
SHIFT_OPENEDShift opened by admin
SHIFT_CLOSEDShift closed
ORDER_CREATEDNew bar order
PAYMENT_RECEIVEDIncoming payment

Full up-to-date list via introspection:

{
__type(name: "WebhookEventType") {
enumValues { name description }
}
}

Each event arrives as a POST with a JSON body:

{
"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"
}
}

Fields id, type, timestamp, clubId are always present. The content of data depends on event type.

Every IZI request contains an X-IZI-Signature header — HMAC-SHA256 of the request body signed with your secret.

const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
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');
});

Important: use express.raw() or equivalent — you need the raw body for correct signature verification. Parsing JSON before checking will break the signature.

IZI delivers events with at-least-once guarantee. A single event may arrive twice due to network issues. Guard against duplicates:

const processedEvents = new Set(); // in production — Redis or DB
async function processEvent(event) {
if (processedEvents.has(event.id)) {
return; // skip duplicate
}
await handleEvent(event);
processedEvents.add(event.id);
}

Use the event.id field as your idempotency key.

If your endpoint doesn’t respond 200 OK within 5 seconds, IZI retries:

AttemptDelay
230 seconds
35 minutes
430 minutes
52 hours
624 hours

After 6 failed attempts, the webhook enters FAILED status. To reactivate:

mutation ReactivateWebhook($id: ID!) {
updateWebhook(id: $id, input: { isActive: true }) {
id
isActive
}
}

List all webhooks for the organization:

query ListWebhooks {
webhooks {
id
url
events
isActive
lastDeliveredAt
failureCount
}
}

Delete:

mutation DeleteWebhook($id: ID!) {
deleteWebhook(id: $id) {
success
}
}
Terminal window
# Install ngrok
brew install ngrok
# Open tunnel
ngrok http 3000
# Use the generated URL when creating the webhook
# https://abc123.ngrok.io/izi/events

Perguntas frequentes

Which events support webhooks?

SESSION_STARTED, SESSION_ENDED, BALANCE_TOPPED_UP, TARIFF_PURCHASED, DEVICE_STATUS_CHANGED, CLIENT_REGISTERED — and about 15 more event types. Full list via introspection: __type(name: WebhookEventType).

What does IZI do if my endpoint doesn't respond?

IZI retries with exponential backoff: 30 sec, 5 min, 30 min, 2 hours, 24 hours. After 5 failed attempts, the webhook is marked as failed and requires manual reactivation.

Can I subscribe to events from a specific club only?

Yes. When creating a webhook, specify clubId — events will be scoped to that club. Without clubId, you receive events for all clubs in the organization.

How do I test webhooks locally?

Use ngrok or Cloudflare Tunnel to get a temporary public URL. Replace it with your production endpoint later.