Webhook Events
Topic catalogue
Points
Topic | Fires when |
|---|---|
| A customer earns points from any earning rule |
| A customer spends points on a reward |
| Points expire under the expiration policy |
| Points are taken back because an order was refunded, cancelled, or unfulfilled |
| A balance changes outside the rules above — admin edit, import, store credit, or Shopify Flow |
| Scheduled reminder that a balance is about to expire |
Customer
Topic | Fires when |
|---|---|
| A customer joins the loyalty programme |
VIP tiers
Topic | Fires when |
|---|---|
| A customer moves up a VIP tier |
| A customer moves down a VIP tier |
| A customer is at risk of losing their tier |
| A tier perk or reward is issued to a customer |
Rewards
Topic | Fires when |
|---|---|
| Scheduled reminder that a reward is about to expire |
Referrals
Topic | Fires when |
|---|---|
| A customer sends a referral invitation |
| A referrer is rewarded for a successful referral |
| A referred friend claims their welcome reward |
Birthday
Topic | Fires when |
|---|---|
| A birthday reward is issued |
| A customer's birthday is set or changed |
Event payloads
points/earned
Field | Type | Description |
|---|---|---|
| number | Points actually added, always positive. The final figure, after every modifier below |
| number | Points before the limited-time-offer multiplier. Equals |
| string | The earning rule that awarded the points |
| number | Shopify order id, when the rule is order-driven |
| object | The limited-time offer that multiplied this award, or |
| object | The VIP tier rate used instead of the rule's own rate, or |
{
"oldPoints": 1350,
"newPoints": 1650,
"activityType": "earn_point",
"settingType": "place_order",
"points": 300,
"basePoints": 150,
"earningRuleId": "66c9f21b7e5a4d0193bc2210",
"orderId": 5512094318721,
"lto": {
"id": "66e40a12c7b1f5039a2d6611",
"name": "Double Points Weekend",
"pointMultiplier": 2
},
"vipEarning": {
"earnPoint": 2,
"spent": 1
}
}
The two apply at different stages, so one event can carry both:
vipEarningreplaces the earning rule's own rate. When the customer's tier grants a better rate, they earnearnPointpoints perspentof order value instead of the rate configured on the rule. That is whatbasePointsis calculated from.ltothen multiplies the result:points = basePoints × lto.pointMultiplier.nullon either field means the modifier was not applied — not that it is unknown.
points/redeemed
Field | Type | Description |
|---|---|---|
| number | Points spent, always positive |
| string | The redemption rule used |
On this topic settingType is the reward type: amount, percentage, shipping, free_product, store_credit, or redirect_url.
{
"oldPoints": 1500,
"newPoints": 1000,
"activityType": "redeem_point",
"settingType": "amount",
"pointsRedeemed": 500,
"redeemRuleId": "66ca0374b19f8c02d47ae115"
}
points/expired
Field | Type | Description |
|---|---|---|
| number | Points removed, always positive |
{
"oldPoints": 1000,
"newPoints": 800,
"activityType": "adjust_point",
"settingType": "point_expiration",
"pointsExpired": 200
}
points/reversed
Field | Type | Description |
|---|---|---|
| number | Points taken back, always positive |
| string |
|
| number | The order that triggered the reversal |
| string | The rule that originally awarded the points |
{
"oldPoints": 800,
"newPoints": 650,
"activityType": "adjust_point",
"settingType": "refunded",
"pointsReversed": 150,
"reason": "refunded",
"orderId": 5512094318721,
"earningRuleId": "66c9f21b7e5a4d0193bc2210"
}
points/adjusted
Field | Type | Description |
|---|---|---|
| number | Signed delta — negative when points were removed |
| string |
|
| string | Reason recorded with the adjustment |
| string | Free-text note recorded with the adjustment |
{
"oldPoints": 650,
"newPoints": 900,
"activityType": "adjust_point",
"settingType": null,
"points": 250,
"source": "admin",
"reason": "Goodwill credit",
"note": "Ticket #4821"
}
points/expiring_soon
Field | Type | Description |
|---|---|---|
| number | Points due to expire |
| string | ISO 8601 timestamp of the expiry |
| number | Days until the points expire |
{
"pointsExpiring": 900,
"expiresAt": "2026-09-24T00:00:00.000Z",
"daysRemaining": 30
}
customer/joined
Field | Type | Description |
|---|---|---|
| string |
|
| number | Sign-up bonus awarded, |
{
"source": "storefront",
"pointsEarned": 100
}
tier/upgraded and tier/downgraded
Both topics carry the same fields.
Field | Type | Description |
|---|---|---|
| object |
|
| object |
|
| string | What the VIP programme measures: |
| string |
|
{
"previousTier": { "id": "66d1b4e7c2a9f80315de7740", "name": "Silver", "targetValue": 500 },
"currentTier": { "id": "66d1b4e7c2a9f80315de7742", "name": "Gold", "targetValue": 1500 },
"achieveType": "point",
"source": "points"
}
tier/demotion_reminder
Field | Type | Description |
|---|---|---|
| object |
|
| number | The customer's progress against |
| number | Days left to requalify |
{
"tierAtRisk": { "id": "66d1b4e7c2a9f80315de7742", "name": "Gold", "targetValue": 1500 },
"currentValue": 1120,
"daysRemaining": 7
}
tier/perk_granted
Field | Type | Description |
|---|---|---|
| object |
|
| string |
|
| string | The VIP discount rule that issued it |
{
"reward": {
"id": "66f2c9a4b81d3e0217af7c58",
"code": "GOLD-9F2A4C",
"name": "Gold members: 15% off",
"discountType": "percentage", # amount | percentage | shipping | free_product | custom | bonus_points
"value": 15,
"expiresAt": "2026-09-30T23:59:59.000Z"
},
"perkType": "vip_perk",
"vipDiscountId": "66d1c07fa4b2e5031f8ac913"
}
reward/expiring_soon
Field | Type | Description |
|---|---|---|
| object |
|
| number | Days until the reward expires |
{
"reward": {
"id": "66f2c9a4b81d3e0217af7c58",
"code": "GOLD-9F2A4C",
"name": "Gold members: 15% off",
"expiresAt": "2026-09-01T23:59:59.000Z"
},
"daysRemaining": 7
}
referral/invite_sent
The customer in the envelope is the referrer.
Field | Type | Description |
|---|---|---|
| string | The referrer's code |
| string | The shareable referral URL |
| string | Email the invitation was sent to |
{
"referralCode": "MAI-4F2A",
"referralLink": "https://example-store.com?bloy_ref=MAI-4F2A",
"invitedEmail": "friend@example.com"
}
referral/reward_earned
The customer in the envelope is the referrer.
Field | Type | Description |
|---|---|---|
| string | Always |
| string | The referrer's code |
| string | Always |
| number | Points awarded for the referral |
| string | Name of the referral earning rule |
{
"role": "referrer",
"referralCode": "MAI-4F2A",
"rewardType": "points",
"pointsEarned": 200,
"earningName": "Refer a friend"
}
referral/referee_claimed
The customer in the envelope is the referred friend.
Field | Type | Description |
|---|---|---|
| string | Always |
| string | Always |
| string | The discount code issued |
| string | Human-readable description of the reward |
| number | Value of the discount |
{
"role": "referee",
"rewardType": "coupon",
"couponCode": "WELCOME-7B1E",
"rewardName": "10% off your first order",
"discountValue": 10
}
birthday/reward_earned
Field | Type | Description |
|---|---|---|
| string |
|
| number | Points awarded, |
{
"rewardType": "points",
"pointsEarned": 500
}
birthday/updated
Field | Type | Description | |
|---|---|---|---|
| string | null | The new birthday as stored, ISO 8601, |
{
"birthday": "1994-03-18T00:00:00.000Z"
}
Updated on: 26/08/2026
Thank you!
