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.

EventWhen
order.completedFires after fulfillOrder() flips the order to `fulfilled`. Payload is the full order object.
order.refundedFires after a charge.refunded webhook reconciles. Payload includes the updated order with `partially_refunded` / `refunded` status.
gift_card.issuedFires the first time a gift card row is created for an order item. Webhook re-deliveries from Stripe don't double-fire.
gift_card.redeemedFires every time the balance is decremented. Payload includes the updated gift card and the `redeemed_amount_cents`.
ticket.issuedOne 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.redeemedFires 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.
ticket_event.cancelledFires once when a merchant cancels an event occurrence. Every holder's tickets are voided and paid ones refunded — a paired `order.refunded` fires per affected paid order. Payload includes the event `id`, `product_id`, `event_at`, and counts (`orders_refunded`, `tickets_voided`, `total_refunded_cents`).
booking.confirmedFires after a booking is issued (post-fulfillment). For slot-based bookings, payload's `ticket_event_id` is set; for multi-pass walk-in bookings (`max_uses > 1`) it's `null` — no slot was reserved at purchase.
booking.redeemedFires 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.
booking.rescheduledFires when a booking's time is changed — by the customer from their confirmation link or by the merchant. Payload is the updated booking with its new `starts_at` / `ends_at`.
booking.cancelledFires when a booking is cancelled — by the customer (within the cancellation cutoff) or by the merchant. Payload is the updated booking with `voided_at` set; any refund follows the product's refund-on-cancel policy.
voucher.issuedFires 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.redeemedFires 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.
experience_gift.issued
experience_gift.redeemed
experience_gift.voided
waiver.issuedFires once per attendee at fulfilment when a booking/ticket product requires a liability waiver. Payload includes the waiver `id`, `order_id`, `attendee_index`, `status: "pending"`, and a `sign_url` for that attendee's signing page.
waiver.signedFires when an attendee completes and signs their waiver. Payload includes the waiver `id`, `order_id`, `attendee_index`, `status: "signed"`, and `signed_at`.
membership.activatedFires on first activation (status transitioned to `active` or `trialing`). Renewals don't re-fire.
membership.cancelledFires when the membership transitions to `canceled`.
membership.checkin.createdFires 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.shippedFires 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.
merchant.deletion_requested
merchant.deletion_cancelled
merchant.stripe_disconnected