Register an endpoint
Create an endpoint with the events you want. The response includes the signing secret once - store it immediately; it is never returned again.Endpoint id (use it to delete the endpoint).
Your HTTPS delivery URL.
The subscribed event names.
SANDBOX or LIVE, from the key you used.The HMAC signing secret, prefixed
whsec_. Shown once - store it now.ISO-8601 creation time.
GET /v1/webhooks (list) and DELETE /v1/webhooks/{id}.
An org may hold up to 10 active endpoints per environment. See the
API reference.
Event catalog
Theredemption.* names cover the full booking lifecycle - one event per status
transition - so a CRM sees the whole course of an experience.
| Event | Fires when |
|---|---|
redemption.created | A redemption is submitted. |
redemption.open | It moves to open. |
redemption.awaiting_vendor | It is waiting on the vendor. |
redemption.awaiting_customer | It is waiting on the customer. |
redemption.purchased | It is purchased (sometimes called “confirmed”; purchased is canonical). |
redemption.completed | The experience completed. |
redemption.canceled | It was canceled (points are refunded). |
wallet.credited | Points were credited to a member. |
wallet.debited | Points were debited (for example, a redemption spend). |
member.created | A member profile was created. |
member.tier_changed | A member’s tier changed. |
member.removed | A member was removed. |
conversation.message_created | A new concierge message was created. |
Subscribing to an event name not in this catalog is rejected with
WEBHOOK_EVENT_UNKNOWN. A non-HTTPS or disallowed URL is rejected with
WEBHOOK_URL_NOT_ALLOWED.Delivery format
Each delivery is aPOST with a JSON body and these headers:
| Header | Value |
|---|---|
X-Expys-Signature | sha256=<hex> HMAC-SHA256 of the exact raw body. |
X-Expys-Timestamp | Delivery timestamp (use to reject stale replays). |
X-Expys-Event | The event name (for example redemption.created). |
X-Expys-Delivery | A unique delivery id (use it for idempotent consumption). |
Verify the signature
Recompute HMAC-SHA256 over the exact raw request body (not a re-serialized object) with your signing secret, hex-encode it, prefixsha256=, and compare in
constant time against X-Expys-Signature.
Retries and dead-lettering
A delivery is retried on any non-2xx response or timeout, with exponential backoff: first retry after 30s, doubling each time, capped at 1 hour. After 6 total attempts the delivery is dead-lettered and no longer retried.Each delivery request times out after 10 seconds, so respond quickly. Do the
real work asynchronously - acknowledge with a 2xx as soon as you have verified
the signature and enqueued the event.
Consume idempotently
Deliveries are at-least-once: a retry can arrive after you already processed an event. Deduplicate onX-Expys-Delivery (or the event’s own id) and make
handlers idempotent so a duplicate is a no-op.