type and what sits inside data.object. Everything else is constant.
The envelope
Unique id for this delivery. A resend of the same logical event uses a brand-new id, not the original.
The event name. See Event types for the full list and what each one means.
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.Unix timestamp in seconds, marking when Boble emitted the event.
true in production, false in any test environment (including a test event you triggered manually outside production).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:| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | Boble-Webhook/1.0 — useful to filter Boble traffic in your access logs. |
Boble-Signature | The HMAC signature of the body. See Signature verification. |
Boble-Event-Id | Matches the id in the body. A resend of an event uses a new id. |
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
| Field | Description |
|---|---|
id | UUID of the buyer. |
email | Buyer’s email address. May be null if the account was deleted. |
firstname | First name. May be null. |
lastname | Last name. May be null. |
username | Username on Boble. May be null. |
avatar | Full URL of the avatar. null when not set. |
preferred_language | IETF code: en, fr, es. May be null. |
created_at | ISO-8601 timestamp of the buyer’s account creation. May be null. |
promotion object
| Field | Description |
|---|---|
id | UUID of the promotion. |
title | Title of the promotion. |
type | free, one_time, or subscription. |
currency | ISO-4217 code in uppercase: EUR, USD, GBP. |
amount | Price in the promotion’s currency. null for free promotions. |
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.