Webhook event types
The full list of events Zillo emits today. Adding a new event is a code change, not a migration — check back here when integrating.
| Event | When |
|---|---|
| order.completed | Fires after fulfillOrder() flips the order to `fulfilled`. Payload is the full order object. |
| order.refunded | Fires after a charge.refunded webhook reconciles. Payload includes the updated order with `partially_refunded` / `refunded` status. |
| gift_card.issued | Fires the first time a gift card row is created for an order item. Webhook re-deliveries from Stripe don't double-fire. |
| gift_card.redeemed | Fires every time the balance is decremented. Payload includes the updated gift card and the `redeemed_amount_cents`. |
| ticket.issued | One event per ticket on first issuance. Payload includes `qr_token` and `max_uses` (1 for single-entry tickets; >1 for multi-day or multi-entry passes — e.g. a 3-day festival pass). |
| ticket.redeemed | Fires on EVERY scan, not just the first — multi-entry tickets (`max_uses > 1`) emit one event per scan. Payload includes the updated ticket (with live `uses_after` / `remaining`) plus `was_first: true|false` so subscribers can distinguish opening scans from subsequent re-entries. |
| booking.confirmed | Fires after a booking is issued (post-fulfillment). For slot-based bookings, payload's `experience_slot_id` is set; for multi-pass walk-in bookings (`max_uses > 1`) it's `null` — no slot was reserved at purchase. |
| booking.redeemed | Fires on EVERY scan, not just the first — multi-pass walk-in bookings (`max_uses > 1`, e.g. 10-class yoga pack) emit one event per visit. Payload includes the updated booking (with live `uses_after` / `remaining`) plus `was_first: true|false` so subscribers can distinguish first scans from subsequent punches. |
| voucher.issued | Fires the first time a voucher row is created for an order item. Payload includes `max_uses` (1 for single-use; >1 for prepaid packs like a 5-class yoga pass). |
| voucher.redeemed | Fires on EVERY scan, not just the first — multi-use packs (`max_uses > 1`) emit one event per redemption. Payload includes the updated voucher (with live `uses_after` / `remaining`), the new `redemption` event row, and `was_first: true|false` so subscribers can distinguish opening scans from subsequent ones. |
| membership.activated | Fires on first activation (status transitioned to `active` or `trialing`). Renewals don't re-fire. |
| membership.cancelled | Fires when the membership transitions to `canceled`. |
| membership.checkin.created | Fires every time a check-in is recorded (append-only, not idempotent). On plans with a per-period cap (`max_checkins_per_period` — e.g. '5 classes a month'), payload includes a `usage` block with the live count, remaining allowance, and refill date. Capped plans reject scans beyond the allowance at the API layer (409 `exhausted`), so this event only fires for successful check-ins. |
| order.shipped | Fires when a merchant marks an order's physical-product lines shipped from the dashboard. Payload is the full order object plus the `tracking_number` and `carrier` entered at ship time (either may be null). Re-marking an already-shipped order is a no-op and doesn't re-fire. |
| digital_product.issued | Fires the first time download tokens are minted for a digital-product order line (at fulfillment). Payload includes `order_id`, `order_item_id`, `product_id`, and `file_count`. Re-deliveries don't re-fire. The buyer separately receives secure, expiring download links by email. |