# Webhook Events

## Available topics

{% hint style="info" %}
**Total Events Available:** 19 webhook topics covering all major loyalty program interactions
{% endhint %}

Joy Loyalty supports the following webhook topics for real-time event notifications:

| Topic                            | Description                      | Trigger                                                     |
| -------------------------------- | -------------------------------- | ----------------------------------------------------------- |
| `points/earned`                  | Customer earns points            | When points are added to customer account                   |
| `points/redeemed`                | Customer redeems points          | When points are used to redeem rewards                      |
| `points/expired`                 | Points expired                   | When customer's points expire and are deducted              |
| `points/about_to_expire_3_days`  | Points about to expire (3 days)  | 3 days before points expiration                             |
| `points/about_to_expire_7_days`  | Points about to expire (7 days)  | 7 days before points expiration                             |
| `points/about_to_expire_30_days` | Points about to expire (30 days) | 30 days before points expiration                            |
| `customer/status_changed`        | Customer status changed          | When customer joins, rejoins, or leaves loyalty program     |
| `reward/coupon_used`             | Coupon used                      | When customer uses a Joy coupon to place an order           |
| `tier/upgraded`                  | Customer tier upgraded           | When customer is upgraded to a higher tier                  |
| `tier/downgraded`                | Customer tier downgraded         | When customer is demoted to a lower tier                    |
| `tier/reset`                     | Tier reset                       | When customer's tier is reset according to scheduled reset  |
| `tier/about_to_reset_4_weeks`    | Tier about to reset (4 weeks)    | 4 weeks before tier reset                                   |
| `tier/about_to_reset_2_weeks`    | Tier about to reset (2 weeks)    | 2 weeks before tier reset                                   |
| `tier/about_to_reset_1_day`      | Tier about to reset (1 day)      | 1 day before tier reset                                     |
| `referral/link_created`          | Referral link created            | When customer creates a referral link for the first time    |
| `referral/reward_earned`         | Referral reward earned           | When referrer receives reward after referee completes order |
| `referral/referee_claimed`       | Referee claimed reward           | When referee claims coupon reward                           |
| `birthday/reward_earned`         | Birthday reward earned           | When customer receives birthday reward                      |
| `milestone/achieved`             | Milestone achieved               | When customer achieves a milestone                          |

## Webhook delivery

When a loyalty event occurs, Joy automatically sends a POST request to your registered webhook endpoints with the following characteristics:

* **HTTP Method**: POST
* **Content-Type**: application/json
* **Timeout**: 5 seconds maximum response time
* **Retry Logic**: Failed webhooks are retried with exponential backoff
* **Security**: All requests include HMAC signature for verification

### Request headers

Every webhook request from Joy includes these headers:

```http
Content-Type: application/json
X-Joy-Loyalty-Shop-Source-Id: your_shop_source_id
X-Joy-Loyalty-Hmac-Sha256: signature_hash
X-Joy-Loyalty-Topic: webhook_topic
```

**Header Descriptions:**

| Header                         | Description                                      |
| ------------------------------ | ------------------------------------------------ |
| `Content-Type`                 | Always set to `application/json`                 |
| `X-Joy-Loyalty-Shop-Source-Id` | Your shop's unique identifier in Joy system      |
| `X-Joy-Loyalty-Hmac-Sha256`    | HMAC-SHA256 signature for verifying authenticity |
| `X-Joy-Loyalty-Topic`          | The webhook topic that triggered this request    |

### Base payload structure

All webhook payloads include these common fields:

```json
{
  "webhookId": "unique_webhook_id",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "activity_id",
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

## Event payload examples

### Points events

#### points/earned

```json
{
  "topic": "points/earned",
  "shopDomain": "myshop.myshopify.com",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "data": {
    "customerId": "gid://shopify/Customer/123456",
    "email": "customer@example.com",
    "points": 100,
    "totalPoints": 1500,
    "source": "order",
    "orderId": "gid://shopify/Order/789"
  }
}
```

#### points/redeemed

```json
{
  "topic": "points/redeemed", 
  "shopDomain": "myshop.myshopify.com",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "data": {
    "customerId": "gid://shopify/Customer/123456",
    "email": "customer@example.com",
    "pointsRedeemed": 500,
    "remainingPoints": 1000,
    "rewardType": "discount",
    "rewardValue": "$5 OFF"
  }
}
```

#### points/expired

```json
{
  "webhookId": "activity_xyz789",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe", 
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "activity_xyz789",
  "oldPoint": 500,
  "newPoint": 0,
  "type": "expire_point",
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

#### points/about\_to\_expire

```json
{
  "webhookId": "about_to_expire_customer123_1705312200000",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "about_to_expire_customer123_1705312200000", 
  "type": "points_about_to_expire",
  "point": 500,
  "expiredAt": "2024-01-22T00:00:00.000Z",
  "daysUntilExpiration": 7,
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

### Customer events

#### customer/status\_changed

```json
{
  "topic": "customer/status_changed",
  "shopDomain": "myshop.myshopify.com",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "data": {
    "customerId": "gid://shopify/Customer/123456",
    "email": "customer@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "type": "user_joined",
    "tier": "Bronze"
  }
}
```

**Possible type values:**

* `user_joined`: Customer joins loyalty program for the first time
* `user_rejoined`: Customer rejoins after leaving
* `user_excluded`: Customer is excluded from loyalty program

### Reward events

#### reward/coupon\_used

```json
{
  "webhookId": "activity_xyz789",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "activity_xyz789",
  "type": "place_order_with_coupon",
  "couponCode": "JOY-ABC123",
  "orderId": 123456789,
  "orderNumber": 1001,
  "orderName": "#1001",
  "orderSubTotal": "99.99",
  "orderCurrency": "USD",
  "programTitle": "10% Off Discount",
  "redeemPoint": 500,
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

### Tier events

#### tier/upgraded

```json
{
  "webhookId": "activity_xyz789",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "activity_xyz789",
  "type": "update_tier",
  "oldTierId": "tier_bronze_123",
  "oldTierName": "Bronze",
  "newTierId": "tier_silver_456", 
  "newTierName": "Silver",
  "tierPoint": 1500,
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

#### tier/downgraded

```json
{
  "webhookId": "activity_xyz789",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "activity_xyz789",
  "type": "demote_tier",
  "oldTierId": "tier_gold_789",
  "oldTierName": "Gold",
  "newTierId": "tier_silver_456",
  "newTierName": "Silver", 
  "tierPoint": 800,
  "reason": "reassessment",
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

### Referral events

#### referral/link\_created

```json
{
  "webhookId": "referral_link_customer123_1705312200000",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "referral_link_customer123_1705312200000",
  "type": "referral_link_created",
  "referralCode": "abc123xyz",
  "urlReferral": "https://myshop.myshopify.com?ref=abc123xyz",
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

#### referral/reward\_earned

```json
{
  "webhookId": "referral_reward_customer123_1705312200000",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "referrer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "referral_reward_customer123_1705312200000",
  "type": "referral_reward_earned",
  "referredCustomerEmail": "referee@example.com",
  "rewardType": "point",
  "earnPoints": 500,
  "couponCode": null,
  "orderId": "gid://shopify/Order/789",
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

### Birthday events

#### birthday/reward\_earned

Points reward example:

```json
{
  "webhookId": "birthday_reward_customer123_1705312200000",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "birthday_reward_customer123_1705312200000",
  "type": "earn_point",
  "event": "birthday",
  "source": "user",
  "earnPoints": 100,
  "oldPoint": 500,
  "newPoint": 600,
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

Discount reward example:

```json
{
  "webhookId": "5QIhElOglJOCfyX6Zo6I",
  "triggeredAt": "2026-02-06T09:16:33.341Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe", 
    "shopifyCustomerId": 9127686570181
  },
  "id": "5QIhElOglJOCfyX6Zo6I",
  "source": "user",
  "event": "birthday", 
  "type": "earn_DISCOUNT",
  "createdAt": "2026-02-06T09:16:33.341Z"
}
```

### Milestone events

#### milestone/achieved

```json
{
  "webhookId": "activity_xyz789",
  "triggeredAt": "2024-01-15T10:30:00.000Z",
  "customer": {
    "email": "customer@example.com",
    "name": "John Doe",
    "shopifyCustomerId": "gid://shopify/Customer/123456"
  },
  "id": "activity_xyz789",
  "type": "earn_point",
  "event": "milestone",
  "earnBy": "order_count",
  "oldPoint": 1000,
  "newPoint": 1100,
  "programTitle": "Order Milestone Rewards",
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```
