App API
Webhook event types
Every event type unPLUG sends, when it fires and what the payload looks like. Write the handler for each type you subscribe to from the payloads below.
Available at launch
The examples follow one guest, Maya Lopez, through the order on Checkout and orders. She has 420 Beans and 1,880 lifetime Beans on the Green tier, uses the Fall pastry from her wallet on app order app-30417, earns 90 Beans on the $9.00 left after the discount, and later gets a full refund.
Envelope#
Every webhook body is an event object:
{
"id": "7f3a9c2e-4b8d-4e16-a0c5-1d6b8e2f9a47",
"type": "points.changed",
"created_at": "2026-11-05T14:08:52Z",
"api_version": "v1",
"livemode": true,
"brand_id": "e5a1c7d9-2f4b-4c8e-a3d6-8b0f1e9c2a57",
"data": {
"object": { },
"previous_attributes": { }
}
}| Field | Description |
|---|---|
idstring (uuid) | Unique per event. Same as the webhook-id header. Dedupe on it. |
typestring | One of the types below. The list may grow; return 200 for types you don't handle. |
created_atstring | When the change happened, not when it was delivered. Use it to order events. |
api_versionstring | v1. |
livemodeboolean | true in production, false in the sandbox. |
brand_idstring (uuid) | Your brand. |
data.objectobject | A snapshot of the resource at created_at. Each type below says which resource. |
data.previous_attributesobject | On update events, the old values of the fields that changed. Empty on other events. |
Snapshots can be stale by the time you process them. When you need the current state, read the resource from the API.
Headers#
Webhooks follow the Standard Webhooks spec.
| Header | Example | Meaning |
|---|---|---|
webhook-id | 7f3a9c2e-4b8d-4e16-a0c5-1d6b8e2f9a47 | The event id. The same on every retry and redelivery. |
webhook-timestamp | 1793887732 | Unix seconds when this attempt was sent. New on every attempt. |
webhook-signature | v1,h040RAsmDKEcqk4Lh13vuOrVBK9yBovp0Tduidp9DrE= | Base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw body}. Space-separated list of entries during a secret rotation. |
Content-Type | application/json | The body is UTF-8 JSON. |
How to check the signature, with code: Verify the signature.
All event types#
| Type | Fires when | Status |
|---|---|---|
member.created | A member is enrolled | Available at launch |
member.updated | Profile fields or status change | Available at launch |
member.deleted | A deletion completes | Available at launch |
points.changed | Any activity entry is written | Available at launch |
points.expiring | Points are about to expire | Coming soon |
tier.changed | A member moves up or down a tier | Available at launch |
reward.issued | A reward lands in a wallet | Available at launch |
reward.redeemed | A redemption is captured by an order | Available at launch |
reward.expiring | 3 days before a wallet item expires | Available at launch |
order.credited | An order earns points | Available at launch |
order.refunded | An order is refunded, in part or in full | Available at launch |
communication_preferences.updated | A marketing opt-in changes | Available at launch |
challenge.joined | A member joins a challenge | Coming soon |
challenge.progressed | Challenge progress moves | Coming soon |
challenge.completed | A member completes a challenge | Coming soon |
referral.completed | A referred guest qualifies | Coming soon |
webhook.test | You ask for a test event | Available at launch |
Offers granted to a member fire reward.issued with "source": "offer". There is no separate offer event.