Skip to main content
Every event Boble sends to your endpoint follows the same structure. The fields that change between events are the 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

All user_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, the data.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 same data.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.