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.

HeaderDescription
x-loyaltylion-site-domainThe domain of the associated site, for example, shop.example.com
x-loyaltylion-topicFor example, customers/update
x-loyaltylion-hmac-sha256An HMAC to verify the request authenticity and payload
user-agentWill 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:

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

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.

FieldTypeDescription
customerobjectA 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.

FieldTypeDescription
idintegerUnique ID of customer in LoyaltyLion nested under customer
emailstringEmail 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.

FieldTypeDescription
customerobjectA customer object
previous_tierobjectThe previous tier of the customer, a loyalty tier object
new_tierobjectThe 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.

FieldTypeDescription
customerobjectA customer object
previous_tierobjectThe previous tier of the customer, a loyalty tier object
new_tierobjectThe 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.

FieldTypeDescription
customerobjectA customer object
available_rewardsarrayArray 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.

FieldTypeDescription
customerobjectA customer object
available_rewardsarrayArray of available reward objects representing all available rewards the customer may claim
points_approved_in_intervalnumberThe number of points the customer has earned within that month
points_interval_start_datestringThe 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.

FieldTypeDescription
customerobjectA customer object
titlestringTitle of the claimed reward
reward_typestringThe type of the claimed reward, either voucher or gift_card
discount_typestringThe type of discount, either percentage, flat or custom
voucher_codestring | nullThe voucher code of the reward claimed. Only present if the claimed reward was a voucher
discount_amountinteger | nullThe discount amount of the claimed reward. Only present if the claimed reward was a voucher
gift_card_last_charactersstring | nullThe final four characters of the gift card applied. Only present if the claimed reward was a gift card
currencystring | nullThe currency of the gift card. Only present if the claimed reward was a gift card
initial_valueinteger | nullThe initial value of the gift card. Only present if the claimed reward was a gift card
balanceinteger | nullThe 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.

FieldTypeDescription
customerobjectA customer object
transactionobjectA transaction object
available_rewardsarrayArray 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.

FieldTypeDescription
referring_customerobjectThe referring customer, a customer object
referred_customerobjectThe new customer that followed the referral link, , a customer object
activityobjectThe associated referral activity, an activity object
orderobjectThe 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.

FieldTypeDescription
referring_customerobjectThe referring customer that started this interaction, a customer object
referred_customerobjectThe new customer that got referred, a customer object
activityobjectObject that represents the activity that was completed, an activity object
orderobject | nullIf the activity was a purchase rule, this is an order object that triggered the referral
reviewobject | nullIf the activity was a review, then this object comprises kind and rating
birthdaystring | nullIf the activity was the birthday rule, then this is an ISO 8601 timestamp
social_linkstring | nullIf 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.

FieldTypeDescription
customerobjectA customer object
current_tierobjectThe current loyalty tier of the customer, a loyalty tier object
next_tierobjectThe loyalty tier that the customer is approaching, a loyalty tier object
points_requiredinteger | nullIf tiers are points-based, the number of points required to reach the next tier
spend_requiredinteger | nullIf 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.

FieldTypeDescription
customerobjectA customer object
new_insight_segmentstringThe insight segment that the customer has just moved to. Equal to Win Back for this webhook.
previous_insight_segmentstring | nullThe tier that the customer has moved from. One of At Risk, Loyal, Win Back or null
frequencyinteger | nullThe number of orders the customer has placed
total_spendinteger | nullThe total lifetime spend of the customer
last_order_datestring | nullAn ISO 8601 string of the last date the customer placed an order
average_basket_sizefloat | nullAverage 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.

FieldTypeDescription
customerobjectA customer object
new_insight_segmentstringThe insight segment that the customer has just moved to. Equal to At Risk for this webhook
previous_insight_segmentstring | nullThe tier that the customer has moved from. One of At Risk, Loyal, Win Back or null
frequencyinteger | nullThe number of orders the customer has placed
total_spendinteger | nullThe total lifetime spend of the customer
last_order_datestring | nullAn ISO 8601 string of the last date the customer placed an order
average_basket_sizefloat | nullAverage 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.

FieldTypeDescription
customerobjectA customer object
new_insight_segmentstringThe insight segment that the customer has just moved to. Equal to Loyal for this webhook
previous_insight_segmentstring | nullThe tier that the customer has moved from. One of At Risk, Loyal, Win Back or null
frequencyinteger | nullThe number of orders the customer has placed
total_spendinteger | nullThe total lifetime spend of the customer
last_order_datestring | nullAn ISO 8601 string of the last date the customer placed an order
average_basket_sizefloat | nullAverage value of the customer’s basket