Webhooks
You can use webhooks to receive notifications about events that happen in LoyaltyLion, such as a customer earning points or moving into a new tier. This is more efficient than polling our API periodically.
Receiving webhooks
Once you have registered a webhook subscription, LoyaltyLion issues an HTTP POST
request to the specified URL every time that event occurs.
Webhooks approaching_tier_upgrade
and reward_available_notification
have a 7 day cool-off period in place.
In practice, this means that once you receive a webhook about a customer approaching a tier upgrade, we will not send another tier upgrade webhook for this customer for at least a week.
The request body is a JSON object containing the webhook metadata and payload.
interface WebhookEventRequestBody {
// a globally unique ID for this webhook event
id: string
// event that triggered this webhook
topic: string
// an ISO 8601 string representing the date this webhook was sent
created_at: string
// a resource-specific payload
payload: any
}
The webhook event payload depends on the topic that triggered the webhook. See webhook topics for details of our available topics and their respective payloads.
In addition to the request body, the request includes the following headers you can use to handle the event.
Header | Description |
---|---|
x-loyaltylion-site-domain | The domain of the associated site, for example, shop.example.com |
x-loyaltylion-topic | For example, customers/update |
x-loyaltylion-hmac-sha256 | An HMAC to verify the request authenticity and payload |
user-agent | Will contain the string LoyaltyLion |
Responding to webhooks
Your app must acknowledge it received the webhook event by responding with an HTTP 200 OK
within 5s.
When we see a response status outside the 2xx range, or a response isn’t received within the 5s timeout, that delivery is considered failed.
Failed webhook events are retried with an exponential backoff until a success response is received or the webhook subscription is removed:
-
After 5 failed attempts, you receive an alert via the email address provided during your OAuth registration.
-
After 30 failed attempts, the webhook subscription is removed and you are notified again.
Verifying webhooks
The webhooks we deliver have a x-loyaltylion-hmac-sha256
header, which is a base64 encoded sha256 HMAC of the raw JSON request body and the relevant secret key:
- If you registered the webhooks with token/secret auth, your site secret
- If you registered the webhooks with an OAuth client, your OAuth client secret
Example typescript code to verify a webhook:
import crypto from 'crypto'
function validate(req: Request, secret: string): boolean {
const requestSignature = req.headers['x-loyaltylion-hmac-sha256']
const ourSignature = crypto
.createHmac('sha256', secret)
.update(Buffer.from(req.body))
.digest('base64')
return requestSignature === ourSignature
}
Managing webhook subscriptions
You can manage webhook subscriptions through our webhook API.
Webhook subscriptions are scoped to the OAuth app (client ID) that created them, that is, an OAuth client can only view their own webhook subscriptions. Webhooks created using token & secret auth are never visible to OAuth clients.
Available actions:
GET /v2/webhooks
Returns a list of all webhook subscriptions for the authenticating scope.
curl \
--url 'https://api.loyaltylion.com/v2/webhooks' \
--header 'Content-Type: application/json'
POST /v2/webhooks
Create a new webhook subscription. You must provide a JSON request body containing the topic
and address
for the new webhook subscription. See webhook topics for a list of available topics.
The address
must be HTTPS.
curl -X POST \
--url 'https://api.loyaltylion.com/v2/webhooks' \
--header 'Content-Type: application/json' \
--data '{
"webhook": {
"topic": "customers/update",
"address": "https://app.example.com/loyaltylion/webhooks"
}
}'
DELETE /v2/webhooks/:id
Delete an existing webhook subscription by id
.
curl -X DELETE \
--url 'https://api.loyaltylion.com/v2/webhooks/7291' \
--header 'Content-Type: application/json'
Webhook topics
The following topics are available for webhook subscriptions:
customers/update
loyalty_emails/unsubscribe
program_events/customer.tier_upgraded
program_events/customer.tier_downgraded
program_events/customer.points_earned
program_events/customer.reward_available_notification
program_events/customer.recurring_reward_available_reminder
program_events/customer.claimed_reward
program_events/customer.referral_complete
program_events/customer.rule_completed
program_events/customer.approaching_tier_upgrade
program_events/customer.moved_to_at_risk_segment
program_events/customer.moved_to_defected_segment
program_events/customer.moved_to_loyal_segment
customers/update
This webhook is fired anytime a customer changes in LoyaltyLion. Examples of when this could fire include earning/redeeming points or moving into a new loyalty tier.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
loyalty_emails/unsubscribe
This webhook is fired anytime a customer unsubscribes from loyalty emails.
To subscribe to this webhook, your access token needs to contain the read_unsubscribes
scope.
Field | Type | Description |
---|---|---|
id | integer | Unique ID of customer in LoyaltyLion nested under customer |
email | string | Email address of customer nested under customer |
program_events/customer.tier_upgraded
This webhook is fired when a customer moves up a tier.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
previous_tier | object | The previous tier of the customer, a loyalty tier object |
new_tier | object | The new tier of the customer, a loyalty tier object |
program_events/customer.tier_downgraded
This webhook is fired when a customer moves down a tier.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
previous_tier | object | The previous tier of the customer, a loyalty tier object |
new_tier | object | The new tier of the customer, a loyalty tier object |
program_events/customer.reward_available_notification
This webhook is fired when the customer has a new reward available. The available_rewards
array contains rewards that are actionable, in stock, enabled and affordable by the customer.
This webhook has a 7 day cool-off period per individual customer in place.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
ⓘ As many customers redeem their points immediately after earning them, this event is only sent after a 5 minute delay.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
available_rewards | array | Array of rewards representing all available rewards the customer may claim |
program_events/customer.recurring_reward_available_reminder
This webhook is fired on a rolling interval, starting 1 month after you first register for it. It will fire for customers on the program who have not received a reward_available_notification
within the same month. The available_rewards
array contains rewards that are actionable, in stock, enabled, and affordable by the customer.
The points_approved_in_interval
property contains the number of points the customer has earned within that month, and the points_interval_start_date
describes when that month started.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
available_rewards | array | Array of available reward objects representing all available rewards the customer may claim |
points_approved_in_interval | number | The number of points the customer has earned within that month |
points_interval_start_date | string | The date that the current interval started in a ISO 8601 format |
program_events/customer.claimed_reward
This webhook is fired when a customer has claimed a reward.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
title | string | Title of the claimed reward |
reward_type | string | The type of the claimed reward, either voucher or gift_card |
discount_type | string | The type of discount, either percentage , flat or custom |
voucher_code | string or null | The voucher code of the reward claimed. Only present if the claimed reward was a voucher |
discount_amount | integer or null | The discount amount of the claimed reward. Only present if the claimed reward was a voucher |
gift_card_last_characters | string or null | The final four characters of the gift card applied. Only present if the claimed reward was a gift card |
currency | string or null | The currency of the gift card. Only present if the claimed reward was a gift card |
initial_value | integer or null | The initial value of the gift card. Only present if the claimed reward was a gift card |
balance | integer or null | The current balance of the gift card. Only present if the claimed reward was a gift card |
program_events/customer.points_earned
This webhook is fired when the customer has earned points.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
ⓘ As many customers redeem their points immediately after earning them, this event is only sent after a 5 minute delay.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
transaction | object | A transaction object |
available_rewards | array | Array of reward objects representing the available rewards for this customer |
program_events/customer.referral_complete
This webhook is fired when a customer follows a referral link and completes an order.
To subscribe to this webhook, your access token needs to contain the read_customers
and read_orders
scopes.
Field | Type | Description |
---|---|---|
referring_customer | object | The referring customer, a customer object |
referred_customer | object | The new customer that followed the referral link, , a customer object |
activity | object | The associated referral activity, an activity object |
order | object | The referred customer’s order that triggered the successful referral, an order object |
program_events/customer.rule_completed
This webhook is fired when a customer completes an activity.
To subscribe to this webhook, your access token needs to contain the read_customers
and read_orders
scopes.
Field | Type | Description |
---|---|---|
referring_customer | object | The referring customer that started this interaction, a customer object |
referred_customer | object | The new customer that got referred, a customer object |
activity | object | Object that represents the activity that was completed, an activity object |
order | object or null | If the activity was a purchase rule, this is an order object that triggered the referral |
review | object or null | If the activity was a review, then this object comprises kind and rating |
birthday | string or null | If the activity was the birthday rule, then this is an ISO 8601 timestamp |
social_link | string or null | If the rule was based on a social media platform, this is the link |
program_events/customer.approaching_tier_upgrade
This webhook is fired when a customer is close to moving up a tier.
This webhook has a 7 day cool-off period per individual customer in place.
To subscribe to this webhook, your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
current_tier | object | The current loyalty tier of the customer, a loyalty tier object |
next_tier | object | The loyalty tier that the customer is approaching, a loyalty tier object |
points_required | integer or null | If tiers are points-based, the number of points required to reach the next tier |
spend_required | integer or null | If tiers are spend-based, the spend required to reach the next tier |
program_events/customer.moved_to_defected_segment
This webhook fires when a customer moves to the Win Back
insight segment. (Note that while the webhook contains the word ‘defected’, the segment is always referred to as Win Back
).
To subscribe to this topic your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
new_insight_segment | string | The insight segment that the customer has just moved to. Equal to Win Back for this webhook. |
previous_insight_segment | string or null | The tier that the customer has moved from. One of At Risk , Loyal , Win Back or null |
frequency | integer or null | The number of orders the customer has placed |
total_spend | integer or null | The total lifetime spend of the customer |
last_order_date | string or null | An ISO 8601 string of the last date the customer placed an order |
average_basket_size | float or null | Average value of the customer’s basket |
program_events/customer.moved_to_at_risk_segment
This webhook fires when a customer moves to the At Risk
insight segment.
To subscribe to this topic your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
new_insight_segment | string | The insight segment that the customer has just moved to. Equal to At Risk for this webhook |
previous_insight_segment | string or null | The tier that the customer has moved from. One of At Risk , Loyal , Win Back or null |
frequency | integer or null | The number of orders the customer has placed |
total_spend | integer or null | The total lifetime spend of the customer |
last_order_date | string or null | An ISO 8601 string of the last date the customer placed an order |
average_basket_size | float or null | Average value of the customer’s basket |
program_events/customer.moved_to_loyal_segment
This webhook fires when a customer moves to the Loyal
insight segment.
To subscribe to this topic your access token needs to contain the read_customers
scope.
Field | Type | Description |
---|---|---|
customer | object | A customer object |
new_insight_segment | string | The insight segment that the customer has just moved to. Equal to Loyal for this webhook |
previous_insight_segment | string or null | The tier that the customer has moved from. One of At Risk , Loyal , Win Back or null |
frequency | integer or null | The number of orders the customer has placed |
total_spend | integer or null | The total lifetime spend of the customer |
last_order_date | string or null | An ISO 8601 string of the last date the customer placed an order |
average_basket_size | float or null | Average value of the customer’s basket |