type and what sits inside data.object. Everything else is constant.
The envelope
string
Unique id for this delivery. A resend of the same logical event uses a brand-new id, not the original.
string
The event name. See Event types for the full list and what each one means.
string
Schema version of the payload. Currently always
2026-01-01. If the schema ever evolves, the new version will be announced and the old one will keep working for a transition period.number
Unix timestamp in seconds, marking when Boble emitted the event.
boolean
true in production, false in any test environment (including a test event you triggered manually outside production).object
The event-specific payload. Its shape depends on
type. The full layout for each event is in Event types.The headers
Boble adds three headers on every delivery:Same buyer everywhere
Alluser_promotion.* events share the same nested user and promotion objects. This means once you’ve written code (or a Zap) to pull the buyer’s email out of one event, the same path works on every event.
user object
promotion object
Same id across the lifecycle
For a given buyer/promotion pair, thedata.object.id stays the same across every event. The first access_granted and a later canceled for the same access will carry the same data.object.id. Use it if you need to track a buyer’s journey across events.
The top-level id (and the Boble-Event-Id header) is unique per delivery — a different one on every event, and a different one again on every resend.
Avoiding double application
Boble does not retry automatically, but a manual resend dispatches a brand-new delivery with the samedata.object but a different envelope id.
If your handler has side effects you don’t want to apply twice (sending a receipt, granting an external role), key your idempotency on a value derived from data.object — typically data.object.id combined with the event type. That way, the original and any resend collapse into the same idempotency key.