Events
Each webhook action subscribes to a specific platform event. When the event fires, Loyal Guru sends a POST request to your endpoint with two custom headers identifying the event type, plus a JSON body.
Available Eventsβ
| Event | LG-Entity | LG-Event | Description |
|---|---|---|---|
| Customer create | customer | create | Fires when a new customer is created |
| Customer update | customer | update | Fires when a customer profile is updated (including automated inactivation) |
| Customer delete | customer | delete | Fires when a customer is deleted or anonymized (including automated inactivity deletion) |
| Customer challenge won | customer | challenge_won | Fires when a customer wins a challenge (threshold reached) |
| Challenge enrolled | challenge | enrolled | Fires when a customer enrolls in a challenge |
| Score trigger | trigger | executed | Fires when a score trigger is executed |
| Refer a friend score trigger | trigger | executed | Fires when a referral score trigger is executed |
| Create profile score trigger | trigger | executed | Fires when a profile creation score trigger is executed |
| Cart create | activity | create | Fires when a purchase (cart) is created |
| Customer tier won | customer | tier_level_won | Fires when a customer reaches a new tier level |
| Customer tier lost | customer | tier_level_lost | Fires when a customer drops to a lower tier level |
| Campaign sent | campaign | delivered | Fires when a Targeted Delivery campaign is sent (campaign_sent trigger) |
| Plan campaign sent | campaign | plan_delivered | Fires per campaign when an Intelligent Delivery plan finishes (plan_campaign_sent trigger) |
| Plan delivered | plan | delivered | Fires once when an Intelligent Delivery plan is delivered (Plan delivered trigger) |
| Voucher created | voucher | created | Fires when a voucher is created in a unit delivery flow (voucher_created trigger) |
| Voucher redeemed | voucher | redeemed | Fires when a voucher is redeemed |
| Reward redeemed | reward | redeemed | Fires when a reward is redeemed |
Customer Eventsβ
Customer Createβ
Headers:
| Header | Value |
|---|---|
| LG-Entity | customer |
| LG-Event | create |
Body fields:
| Field | Description |
|---|---|
id | ID of the customer (integer). Optional if code is present. |
code | Alternative customer identifier (alphanumeric, up to 36 characters) |
name | First name |
surname_1 | First surname |
surname_2 | Second surname |
email | Email address |
phone | Mobile phone number |
phone_prefix | Country phone prefix (required when phone is filled) |
gender | masculine or feminine |
birth | Date of birth. Format: YYYY-MM-DD |
dni | Identification card number |
document_type | Type of identification document |
address | Street address |
address_extra | Additional address info |
city | City |
state | Region / state |
postal_code | Postal code |
country | ISO 3166-1 alpha-2 country code (uppercase) |
preferred_language | ISO 639-1 language code |
status | active / inactive / merged / merging / unverified / deleted |
kind | client or card |
fraudulent | true if the customer is flagged as fraudulent |
terms | true when the customer accepted GDPR terms |
terms_accepted_at | Date when GDPR terms were accepted |
communications | true when the customer accepted receiving communications |
profiling | true when the customer consented to data profiling |
profiling_accepted_at | Date when profiling consent was accepted |
third_party_consent | true if the customer accepted third-party data sharing |
email_unsubscribe | Unsubscribe status for email campaigns |
sms_unsubscribe | Unsubscribe status for SMS campaigns |
push_unsubscribe | Unsubscribe status for push notifications |
paper_free | true if the customer uses digital receipts |
app | true if registration was done via a mobile app |
referred_by | Customer ID of the referrer (must be an existing customer) |
registration_location_id | Registration store ID. Optional if registration_location_code is present. |
registration_location_code | Registration store code |
collective_id | Collective ID |
collective_slug | Collective slug (used only when collective_id is not present) |
attributes | Additional custom attributes stored on the customer |
custom1β¦customN | Custom values configured for the company |
created_at | DateTime of customer creation |
updated_at | DateTime of last update |
Example payload:
{
"address": null,
"address_extra": null,
"birth": null,
"city": null,
"code": null,
"collective_id": null,
"collective_slug": null,
"communications": false,
"country": "ES",
"created_at": "2025-10-21T15:12:24Z",
"custom1": null,
"custom2": null,
"dni": null,
"document_type": null,
"email": null,
"email_unsubscribe": false,
"fraudulent": false,
"gender": null,
"id": "56789112345",
"kind": "client",
"name": "Esther test",
"paper_free": false,
"phone": null,
"phone_prefix": "",
"postal_code": null,
"preferred_language": "es",
"profiling": false,
"profiling_accepted_at": null,
"push_unsubscribe": false,
"referred_by": null,
"app": false,
"registration_location_code": null,
"registration_location_id": 1,
"sms_unsubscribe": false,
"state": null,
"status": "active",
"surname_1": "test2",
"surname_2": null,
"terms": false,
"terms_accepted_at": null,
"updated_at": "2025-10-21T15:12:24Z"
}
Customer Updateβ
Headers:
| Header | Value |
|---|---|
| LG-Entity | customer |
| LG-Event | update |
Same body structure as Customer Create.
Also fires when the Inactivity Lifecycle job sets a Customer to inactive. Plan for additional customer / update volume when a Company enables inactivation.
Customer Deleteβ
Headers:
| Header | Value |
|---|---|
| LG-Entity | customer |
| LG-Event | delete |
Also fires when the Inactivity Lifecycle job anonymizes a Customer (deleted). Soft anonymization uses hard: false. Plan for additional customer / delete volume when a Company enables the delete rule.
Example payload:
{
"customer_code": "123fdrgg",
"customer_id": 134345,
"hard": false
}
Customer Challenge Wonβ
Event generated when a customer wins a challenge (threshold reached).
Headers:
| Header | Value |
|---|---|
| LG-Entity | customer |
| LG-Event | challenge_won |
Body fields:
| Field | Description |
|---|---|
customer.id | Customer ID |
customer.code | Customer code |
customer.score | Updated total balance |
customer.score_available | Updated available balance |
customer_attribute_value | Calculated attribute value for the challenge |
challenge.id | Challenge definition ID |
challenge.name | Challenge name |
challenge.level_id | Achievement definition ID |
challenge.level_name | Achievement level name |
challenge.threshold | Goal value to reach |
challenge.expires_at | Challenge expiration datetime |
challenge.created_at | First win datetime |
challenge.updated_at | Last win datetime |
scores[].score | Points won |
scores[].available_from | Points activation date |
scores[].available_to | Points expiration date |
scores[].loyalty_score_id | Loyalty rule ID applied |
Example payload:
{
"customer": {
"id": 12100002,
"code": "12100002X",
"score": 122389,
"score_available": 122379
},
"customer_attribute_value": 10000,
"challenge": {
"id": 73,
"name": "[Open to all] Run more than 10k",
"level_id": 108,
"level_name": "10000 kms",
"threshold": 10000,
"expires_at": "2024-07-14T23:59:59Z",
"created_at": "2024-05-07T00:00:00Z",
"updated_at": "2024-05-07T08:00:00Z"
},
"scores": [
{
"available_from": "2024-05-07",
"available_to": "2024-06-07",
"score": 100,
"loyalty_score_id": 43219393
}
]
}
Challenge Enrolledβ
Event generated when a customer enrolls in a challenge.
Headers:
| Header | Value |
|---|---|
| LG-Entity | challenge |
| LG-Event | enrolled |
Body fields:
| Field | Type | Description |
|---|---|---|
id | Integer | Enrollment ID |
challenge_id | Integer | Challenge definition ID |
challenge_name | String | Challenge name |
customer_id | Integer | Customer ID |
customer_code | String | Customer code |
enrolled_at | UTC Datetime | Enrollment datetime |
structure[].level | Integer | Achievement level number |
structure[].threshold | Number | Points/value threshold for this level |
structure[].name | String | Level name |
Example payload:
{
"id": 12345,
"challenge_id": 67890,
"challenge_name": "Ultimate Fitness Challenge",
"customer_id": 54321,
"customer_code": "CUST001",
"enrolled_at": "2024-07-29T12:34:56Z",
"structure": [
{ "level": 1, "threshold": 100.0, "name": "Beginner" },
{ "level": 2, "threshold": 200.0, "name": "Intermediate" },
{ "level": 3, "threshold": 300.0, "name": "Advanced" }
]
}
Score Triggerβ
Fires when a score trigger (manual or automated) is executed.
Headers:
| Header | Value |
|---|---|
| LG-Entity | trigger |
| LG-Event | executed |
Body fields:
| Field | Type | Description |
|---|---|---|
slug | String | Slug of the trigger |
comments | String | Comments attached to the trigger |
created_at | String | Event generation timestamp |
total_scores | Integer | Total points awarded |
scores[].loyalty_score_id | Integer | Loyalty rule ID |
scores[].score | Integer | Points awarded by this rule |
scores[].available_from | String | Points validity start date |
scores[].available_to | String | Points validity end date |
customer.id | Integer | Customer ID |
customer.code | String (nullable) | Customer code |
customer.score | Integer | Updated total balance |
customer.score_available | Integer | Updated available balance |
Body example:
{
"slug": "manual",
"comments": "Commercial action",
"created_at": "2024-08-31T15:00:01Z",
"total_scores": 30,
"scores": [
{
"loyalty_score_id": 12,
"score": 30,
"available_from": "2024-01-01",
"available_to": "2025-01-01"
}
],
"customer": {
"id": 12345,
"code": "12345a",
"score": 10,
"score_available": 10
}
}
The Refer a friend and Create profile trigger events share the same header structure (LG-Entity: trigger, LG-Event: executed) as Score trigger, with a slug identifying the specific trigger type (refer_a_friend_executed, after_create_profile).
Cart Eventsβ
Cart Createβ
Headers:
| Header | Value |
|---|---|
| LG-Entity | activity |
| LG-Event | create |
Fires when a purchase (cart) is created via the Streaming API. The body contains the cart payload returned by the platform.
Body example:
{
"id": 5704568633556992,
"currency": "EUR",
"code": "test-ticket-create-post-action-event-0004",
"total": 18.57,
"location_id": 1496,
"customer": {
"id": 10010010124,
"score": 0,
"score_as_money": 0,
"score_available": 0,
"score_available_as_money": 0,
"score_to_reach_cashback": 0,
"money_to_spend_to_reach_cashback": 0,
"score_threshold_cashback": 0,
"score_threshold_cashback_as_money": 0,
"money_threshold_cashback": 0,
"fraudulent": false
},
"creation_date": "2023-06-08T15:14:05Z",
"lines": [
{
"order": 1,
"total": 19.57,
"quantity": 1,
"product_code": "22SMTK055000L",
"original_total": 19.57
},
{
"order": -1,
"total": -1,
"quantity": 1,
"original_total": 0
}
],
"business_name": "testdiporpre",
"score": 0,
"score_as_money": 0,
"score_used": 0,
"score_used_as_money": 0,
"score_returned_to_customer": 0,
"score_returned_to_customer_as_money": 0,
"score_returned_from_customer": 0,
"score_returned_from_customer_as_money": 0,
"custom1": "322001-10456",
"custom3": {
"nested": {
"is": true
},
"test": "test"
},
"custom5": "",
"total_discount_promotion_applied": 1,
"total_discount_applied": 1,
"effects": [
{
"rule_id": 666555922,
"rule_name": "test direct value validator",
"type": "discount",
"effect_type": "direct_value",
"distribution_type": "total",
"value": 100,
"select_customers": "loyalty"
}
]
}
Customer Tier Eventsβ
Customer Tier Wonβ
Fires when a customer reaches a new tier level (threshold reached).
Headers:
| Header | Value |
|---|---|
| LG-Entity | customer |
| LG-Event | tier_level_won |
Body fields:
| Field | Description |
|---|---|
customer.id / customer.code | Customer identity |
customer.score / customer.score_available | Updated points balances |
customer_attribute_value | Calculated attribute value used by the tier |
tier.id / tier.name | Tier definition identifier and name |
tier.level_id / tier.level_name / tier.level_number | Won level details |
tier.threshold | Threshold achieved |
tier.expires_at / tier.created_at / tier.updated_at | Level expiration and win timestamps |
scores[] | Points awarded with the tier win (score, loyalty_score_id, availability dates) |
Body example:
{
"customer": {
"id": 12345,
"code": "CUST123",
"score": 2,
"score_available": 0
},
"customer_attribute_value": 51,
"tier": {
"id": 3,
"name": "Runner",
"level_id": 222,
"level_number": 2,
"level_name": "silver",
"threshold": 50,
"expires_at": "2022-12-31T23:59:59Z",
"created_at": "2022-01-01T00:00:00Z",
"updated_at": "2022-01-01T00:00:00Z"
},
"scores": [
{
"available_from": "2023-01-01",
"available_to": "2023-01-01",
"score": 2,
"line_order": -1,
"loyalty_score_id": 1
}
]
}
Customer Tier Lostβ
Fires when a customer drops to a lower tier level.
Headers:
| Header | Value |
|---|---|
| LG-Entity | customer |
| LG-Event | tier_level_lost |
Body fields:
| Field | Description |
|---|---|
customer_id / customer_code | Customer identity |
attribute_value | Calculated attribute value used by the tier |
current_date | Evaluation timestamp |
current_tier | Current level after the drop (achievement_id, level_name, level_number, level_threshold) |
previous_tier | Previous level (achievement_id, level_name, level_number) |
tier_id / tier_name | Tier definition identifier and name |
expires_at | Current level expiration |
to_reach_next_level / to_reach_next_level_name | Progress needed to regain the next level |
Body example:
{
"attribute_value": 1268.93,
"current_date": "2023-06-20 03:00:00+00:00",
"current_tier": {
"achievement_id": 55,
"level_name": "Silver",
"level_number": 1,
"level_threshold": 0
},
"customer_code": "a97fd304ead449cd94bf5c0524ec121c",
"customer_id": 614472060,
"expires_at": "2025-11-18 22:59:59.999999+00:00",
"previous_tier": {
"achievement_id": 57,
"level_name": "Gold",
"level_number": 2
},
"tier_id": 19,
"tier_name": "DESIGUAL CLUB POLAND",
"to_reach_next_level": 231.07,
"to_reach_next_level_name": "Gold"
}
Campaign Eventsβ
Campaign Sentβ
Fires when a Targeted Delivery (manual) campaign has been sent successfully. In Owner, subscribe with the campaign_sent trigger.
The webhook body includes campaign metadata, a temporary signed URL to the vouchers CSV, checksum, and a promotion snapshot.
Headers:
| Header | Value |
|---|---|
| LG-Entity | campaign |
| LG-Event | delivered |
Body fields:
| Field | Type | Description |
|---|---|---|
campaign_history_id | Integer | ID of the campaign delivery history |
campaign_id | Integer | ID of the sent campaign |
campaign_name | String | Campaign name |
sent_at | Datetime | Campaign delivery time in ISO 8601 format |
voucher_type | String | coupon or discount |
record_count | Integer | Number of records in the exported CSV |
file_url | String | Temporary signed HTTPS URL for downloading the CSV |
file_url_expires_at | Datetime | Expiration of file_url in ISO 8601 format |
checksum | String | MD5 digest of the CSV as lowercase hexadecimal |
promotion | Object | Snapshot of the coupon used by the campaign |
file_url β parse before use. Read file_url by parsing the webhook JSON body (do not extract it from a raw log line or a partially copied string). Use the full value as returned, including all query parameters (for example X-Goog-Signature). Truncating, stripping, or re-encoding the URL invalidates the signature and the download fails.
Body example:
{
"campaign_history_id": 98765,
"campaign_id": 12345,
"campaign_name": "Summer Coupons",
"sent_at": "2026-07-06T10:00:00Z",
"voucher_type": "coupon",
"record_count": 50000,
"file_url": "https://storage.googleapis.com/example/summer-coupons.csv?X-Goog-Signature=abc123",
"file_url_expires_at": "2026-07-07T11:00:00Z",
"checksum": "a3f5c1d9e7b24a6c8f0d123456789abc",
"promotion": {
"id": 54321,
"name": "5 EUR discount",
"coupon_type": "standard",
"discount": 5.5,
"discount_type": "cash",
"available_from": "2026-07-01",
"available_to": "2026-08-31",
"affectation": "activity",
"applies_to": "all",
"min_money": 30.25,
"max_redemptions": 3,
"cumulative": false
}
}
Bulk campaign sends do not emit per-voucher voucher.created events. Use this campaign payload and the CSV download for mass delivery.
Plan Campaign Sentβ
Fires once per campaign when an Intelligent Delivery plan finishes exporting vouchers. In Owner, subscribe with the plan_campaign_sent trigger.
The JSON body uses the same schema as Campaign sent. Distinguish plan campaigns from Targeted Delivery campaigns with the LG-Event header.
Headers:
| Header | Value |
|---|---|
| LG-Entity | campaign |
| LG-Event | plan_delivered |
Body fields and examples: same as Campaign sent.
This is not the same as Plan delivered. Plan campaign sent uses LG-Entity: campaign and fires per campaign inside a plan. Plan delivered uses LG-Entity: plan and fires once for the whole plan.
Plan Deliveredβ
Fires once when an Intelligent Delivery plan has been delivered successfully (including pumps). In the Owner App, subscribe with the Plan delivered trigger.
Use this event when an external system only needs to know that the plan finished β for example, to start a file generation or downstream batch job keyed by plan_id. For per-campaign voucher CSV payloads, use Plan campaign sent instead.
Headers:
| Header | Value |
|---|---|
| LG-Entity | plan |
| LG-Event | delivered |
Body fields:
| Field | Type | Description |
|---|---|---|
plan_id | Integer | ID of the delivered Intelligent Delivery plan |
Example payload:
{
"plan_id": 12345
}
Voucher Eventsβ
Voucher Createdβ
Fires when a voucher is created in a unit delivery flow (manual assignment, game, challenge, reward, or recipe). In the Owner App, subscribe with the voucher_created trigger.
Mass campaign or plan sends do not emit this event per voucher; those flows use Campaign sent / Plan campaign sent plus the CSV file. For plan-level completion only, see Plan delivered.
Headers:
| Header | Value |
|---|---|
| LG-Entity | voucher |
| LG-Event | created |
Body fields:
| Field | Type | Description |
|---|---|---|
created_at | UTC Datetime | Voucher creation time |
origin | String | manual, game, challenge, reward, or recipe |
origin_id | Integer, optional | Identifier of the originating object |
voucher_type | String | coupon or discount |
customer.id | Integer | Customer ID |
customer.code | String | Customer code |
voucher.id | Integer | Voucher ID |
voucher.code | String | Voucher code |
voucher.name | String, optional | Coupon snapshot name |
voucher.status | String | Voucher status |
voucher.discount | Number, optional | Discount value |
voucher.discount_type | String, optional | Discount type |
voucher.available_from | UTC Datetime, optional | Validity start |
voucher.available_to | UTC Datetime, optional | Validity end |
voucher.available_redemptions | Integer, optional | Remaining redemptions |
voucher.affectation | String, optional | Voucher affectation |
voucher.description | String, optional | Voucher description |
coupon.id | Integer | Coupon ID |
coupon.coupon_type | String, optional | Coupon type |
loyalty_rule.id | Integer, discount only | Loyalty rule ID |
loyalty_rule.name | String, discount only | Loyalty rule name |
campaign.id | Integer, optional | Campaign ID |
campaign.campaign_history_id | Integer, optional | Campaign history ID |
campaign.name | String, optional | Campaign name |
campaign.sent_at | UTC Datetime, optional | Campaign delivery time |
campaign.customers | Integer, optional | Number of campaign customers |
Coupon example:
{
"created_at": "2026-07-06T15:00:00Z",
"origin": "game",
"origin_id": 1234,
"voucher_type": "coupon",
"customer": {
"id": 4135,
"code": "CUST-4135"
},
"voucher": {
"id": 78901,
"code": "9900031393759",
"name": "5 EUR en compras >30 EUR",
"status": "pending",
"discount": 5.5,
"discount_type": "cash",
"available_from": "2026-07-01T00:00:00Z",
"available_to": "2026-08-31T23:59:59Z",
"available_redemptions": 1,
"affectation": "activity",
"description": "Valid in purchases over 30 EUR"
},
"coupon": {
"id": 54321,
"coupon_type": "standard"
},
"campaign": {
"id": 12345,
"campaign_history_id": 98765,
"name": "Cupones Verano",
"sent_at": "2026-07-06T10:00:00Z",
"customers": 50000
}
}
Discount example:
{
"created_at": "2026-07-06T15:00:00Z",
"origin": "manual",
"voucher_type": "discount",
"customer": {
"id": 4135,
"code": "CUST-4135"
},
"voucher": {
"id": 78902,
"code": "9900031393760",
"name": "Descuento fidelidad",
"status": "pending",
"available_from": "2026-07-01T00:00:00Z",
"available_to": "2026-08-31T23:59:59Z",
"available_redemptions": 1
},
"coupon": {
"id": 54322
},
"loyalty_rule": {
"id": 24680,
"name": "Descuento fidelidad"
},
"campaign": {
"id": 12345,
"campaign_history_id": 98765,
"name": "Cupones Verano",
"sent_at": "2026-07-06T10:00:00Z",
"customers": 50000
}
}
Voucher Redeemedβ
Headers:
| Header | Value |
|---|---|
| LG-Entity | voucher |
| LG-Event | redeemed |
Body fields:
| Field | Description |
|---|---|
activity_id / activity_code | Cart where the voucher was redeemed |
created_at | Redemption timestamp |
voucher.code | Redeemed voucher code |
voucher.discount / voucher.discount_type | Discount value and type (e.g., percent, cash) |
voucher.available_from / voucher.available_to | Validity window |
voucher.available_redemptions | Remaining redemptions after this use |
voucher.name / voucher.description / voucher.affectation | Voucher details |
customer.id / customer.code | Customer who redeemed the voucher |
Body example:
{
"activity_id": 109977132684614129,
"activity_code": "POS-2026-0415-8831",
"customer": {
"id": 4135,
"code": "CUST-4135"
},
"created_at": "2026-04-15T14:22:03.512Z",
"voucher": {
"code": "9900031393759",
"discount": 12.5,
"discount_type": "percent",
"available_from": "2026-04-10T00:00:00Z",
"available_to": "2026-08-08T23:59:59Z",
"available_redemptions": 2,
"name": "Spring promo 15% off footwear",
"description": "Valid on selected SKUs in store and online.",
"affectation": "category",
"purchased_product_ids": ["100", "200", "201"]
}
}
Reward Eventsβ
Reward Redeemedβ
Headers:
| Header | Value |
|---|---|
| LG-Entity | reward |
| LG-Event | redeemed |
Body fields:
| Field | Description |
|---|---|
redemption_id | Unique redemption ID |
redemption_type | manual or loyalty_rule |
reward.id / reward.name / reward.type | Reward details |
score_used | Points spent on the redemption |
code | Redeemed reward code when applicable |
customer.id / customer.code / customer.score / customer.score_available | Customer identity and updated balances |
created_at | Redemption timestamp |
Body example:
{
"redemption_id": 35,
"redemption_type": "manual",
"reward": {
"id": 835,
"name": "coupon discount 10",
"type": "coupon",
"extra_money": 2.3,
"currency": "EUR"
},
"customer": {
"id": 3232,
"code": "43243jdg6675d",
"score": 10,
"score_available": 10
},
"created_at": "2024-10-01T09:00:00Z",
"score_used": 200,
"code": "Xyguyfuiyuh"
}