# Shopify Flow: Triggers & Actions Reference

{% hint style="info" %}
This feature is available for: **Essential and above**
{% endhint %}

### Overview

Joy Loyalty exposes a set of **triggers** (events fired by Joy) and **actions** (tasks Joy can perform) inside Shopify Flow. Use them to build automated loyalty workflows — no code required.

This page is a complete reference. For step-by-step setup, see [Integrate with Shopify Flow](https://help.joy.so/integrations/integrate-with-shopify-flow).

***

### Trigger data properties

Every Joy trigger passes a common set of customer fields plus event-specific fields. When connecting to an email app (e.g. Klaviyo) through Shopify Flow, **no variable dropdown is shown** — you must type the property names manually. The tables below list every field for each trigger.

{% hint style="info" %}
**Klaviyo template syntax:** Properties from Shopify Flow are available as event properties in Klaviyo. For multi-word property names, use the lookup filter: `{{ event|lookup:'Customer email' }}`. For single-word or underscored names, use dot notation: `{{ event.customer_id }}`.
{% endhint %}

#### Common fields (included in every trigger)

| Property name         | Description                 | Example            |
| --------------------- | --------------------------- | ------------------ |
| `Customer email`      | Customer's email address    | `jane@example.com` |
| `Customer first name` | First name                  | `Jane`             |
| `Customer last name`  | Last name                   | `Doe`              |
| `Customer points`     | Current point balance       | `350`              |
| `customer_id`         | Shopify customer numeric ID | `6123456789`       |

***

#### Earn points

Extra fields beyond the common set:

| Property name   | Description                                     |
| --------------- | ----------------------------------------------- |
| `Program name`  | Name of the earning program that awarded points |
| `Earned points` | Number of points earned in this activity        |
| `Created at`    | Timestamp of the earn event                     |

#### Admin manual point adjustment

| Property name       | Description                 |
| ------------------- | --------------------------- |
| `Adjusted points`   | Points added or subtracted  |
| `Adjustment reason` | Reason entered by the admin |
| `Created at`        | Timestamp of the adjustment |

#### Customer has enough points for reward

| Property name       | Description                         |
| ------------------- | ----------------------------------- |
| `Program id`        | ID of the qualifying reward program |
| `Program name`      | Name of the reward program          |
| `Program min point` | Minimum points required to redeem   |

#### Redeem points

| Property name     | Description                     |
| ----------------- | ------------------------------- |
| `Redeemed points` | Points spent on this redemption |
| `Discount code`   | The discount code generated     |

#### POS point redemption

| Property name     | Description                 |
| ----------------- | --------------------------- |
| `Redeemed points` | Points redeemed at POS      |
| `Discount code`   | The discount code generated |

***

#### 30 / 7 / 3 days before point expiration

| Property name            | Description                       |
| ------------------------ | --------------------------------- |
| `Customer points expire` | Number of points that will expire |

#### Upon point expiration

| Property name            | Description                        |
| ------------------------ | ---------------------------------- |
| `Customer points expire` | Number of points that just expired |

***

#### 7 days before customer's birthday

| Property name             | Description                      |
| ------------------------- | -------------------------------- |
| `Customer birthday date`  | Day of the month (e.g. `14`)     |
| `Customer birthday month` | Month number (e.g. `7` for July) |

#### Customer's birthday

| Property name             | Description                                               |
| ------------------------- | --------------------------------------------------------- |
| `Customer birthday date`  | Day of the month                                          |
| `Customer birthday month` | Month number                                              |
| `Discount code`           | Birthday reward code (if a birthday reward is configured) |

***

#### VIP tier achieved

| Property name   | Description                      |
| --------------- | -------------------------------- |
| `Tier name`     | Name of the tier just achieved   |
| `Discount code` | Tier reward code (if configured) |

#### VIP Tier downgraded / VIP Tier reset

Uses common fields only. No extra properties.

#### Pre-Tier Demotion / Reset Reminders (4w / 2w / 1d)

Uses common fields only. No extra properties.

***

#### Customer comment on Instagram

Fires when Joy detects a customer comment on one of your monitored Instagram posts.

| Field              | Type     | Description                                                                    |
| ------------------ | -------- | ------------------------------------------------------------------------------ |
| `post_id`          | string   | The Instagram post the user commented on                                       |
| `post_url`         | string   | Direct link to the post                                                        |
| `comment_id`       | string   | The comment identifier                                                         |
| `comment_text`     | string   | The text of the comment                                                        |
| `is_first_comment` | boolean  | `true` if this is the user's first comment on this post, `false` otherwise     |
| `comment_count`    | number   | Total number of comments this user has posted on this post, including this one |
| `commented_at`     | datetime | When the comment was created                                                   |

{% hint style="info" %}
Use `is_first_comment` to keep automated DMs from spamming users who comment repeatedly on the same post. In Shopify Flow, add a **Condition** after the trigger: *only continue when `is_first_comment` equals `true`*. Alternatively, use `comment_count` to branch on a custom threshold (e.g., only run on the 3rd comment onwards).
{% endhint %}

#### Customer commented on Instagram Live

Fires when Joy detects a customer comment on your Instagram **Live** broadcast. The payload follows the same shape as the "Customer comment on Instagram" trigger above, including `is_first_comment` and `comment_count`.

#### Referral for friend complete

Fires for the **referrer** when their friend completes a qualifying order.

| Property name          | Description                                                |
| ---------------------- | ---------------------------------------------------------- |
| `Referrer email`       | Email of the referring customer (same as `Customer email`) |
| `Referrer reward type` | Type of reward given (e.g. `points`, `coupon`)             |
| `Referrer reward`      | Value of the reward                                        |
| `order_id`             | Shopify order ID of the friend's order                     |

#### Referee claim reward

Fires for the **new customer** when they claim their referral reward.

| Property name    | Description                           |
| ---------------- | ------------------------------------- |
| `Discount code`  | The reward code issued to the referee |
| `Referrer email` | Email of the friend who referred them |

***

### Triggers — when they fire

#### Points

| Trigger                                   | When it fires                                                         |
| ----------------------------------------- | --------------------------------------------------------------------- |
| **Earn points**                           | A customer earns points from any earning activity                     |
| **Admin manual point adjustment**         | An admin adds or deducts points manually from the customer profile    |
| **Customer has enough points for reward** | A customer's balance crosses the minimum threshold to redeem a reward |
| **Redeem points**                         | A customer redeems points for a discount                              |
| **POS point redemption**                  | A customer redeems points at a physical POS location                  |

#### Point expiration

| Trigger                                      | When it fires                                        |
| -------------------------------------------- | ---------------------------------------------------- |
| **30 days before the point expiration date** | 30 days before a customer's points are set to expire |
| **7 days before the point expiration date**  | 7 days before expiration                             |
| **3 days before the point expiration date**  | 3 days before expiration                             |
| **Upon point expiration**                    | The moment a customer's points expire                |

{% hint style="info" %}
Point expiration triggers only fire if you have point expiration enabled. Go to **Settings > Points** to configure it.
{% endhint %}

#### Birthday

| Trigger                               | When it fires                               |
| ------------------------------------- | ------------------------------------------- |
| **7 days before customer's birthday** | 7 days before the customer's saved birthday |
| **Customer's birthday**               | On the customer's birthday                  |

#### VIP Tiers

| Trigger                               | When it fires                                 |
| ------------------------------------- | --------------------------------------------- |
| **VIP tier achieved**                 | A customer reaches a new VIP tier             |
| **VIP Tier downgraded**               | A customer drops to a lower tier              |
| **VIP Tier reset**                    | A customer's tier resets to the starting tier |
| **4-week Pre-Tier Demotion Reminder** | 4 weeks before scheduled demotion             |
| **2-week Pre-Tier Demotion Reminder** | 2 weeks before demotion                       |
| **1-day Pre-Tier Demotion Reminder**  | 1 day before demotion                         |
| **4-week Pre-Tier Reset Reminder**    | 4 weeks before scheduled tier reset           |
| **2-week Pre-Tier Reset Reminder**    | 2 weeks before reset                          |
| **1-day Pre-Tier Reset Reminder**     | 1 day before reset                            |

{% hint style="info" %}
Demotion and reset reminders only fire when you have a tier evaluation period configured in Joy's VIP Tier settings.
{% endhint %}

#### Referrals

| Trigger                          | When it fires                                         |
| -------------------------------- | ----------------------------------------------------- |
| **Referral for friend complete** | A referred friend places their first qualifying order |
| **Referee claim reward**         | The new customer claims their referral reward         |

#### Social activity

| Trigger                                  | When it fires                                                |
| ---------------------------------------- | ------------------------------------------------------------ |
| **Customer comment on Instagram**        | A customer comments on one of your monitored Instagram posts |
| **Customer commented on Instagram Live** | A customer comments on your Instagram Live broadcast         |

{% hint style="info" %}
Both Instagram comment triggers expose `is_first_comment` and `comment_count` so you can limit automated responses to the first comment per user per post — essential for avoiding spam when a user comments many times.
{% endhint %}

***

### Actions

Actions are tasks that Joy performs when called from a Shopify Flow. All actions require the integration to be **enabled** in Joy > Integrations > Shopify Flow.

#### Points

**Add point** — Adds points to a customer's balance.

| Field    | Required | Description                                |
| -------- | -------- | ------------------------------------------ |
| `email`  | ✅        | Customer's email address                   |
| `point`  | ✅        | Points to add (positive integer)           |
| `reason` | ✅        | Label shown in the customer's activity log |

**Subtract point** — Deducts points (will not go below zero).

| Field                    | Required | Description                            |
| ------------------------ | -------- | -------------------------------------- |
| `email` or `customer_id` | ✅        | Customer email or Shopify customer GID |
| `point`                  | ✅        | Points to subtract                     |
| `reason`                 | —        | Internal note for the activity log     |

#### Store credit

{% hint style="info" %}
Requires granting an additional Shopify permission. When you enable the integration, a banner will prompt you to grant access.
{% endhint %}

**Adjust store credit**

| Field                     | Required | Description                                           |
| ------------------------- | -------- | ----------------------------------------------------- |
| `customer_identification` | ✅        | Customer email or Shopify customer GID                |
| `credits_calculation`     | ✅        | Credit amount (e.g. `10.00` or a Flow variable)       |
| `reason`                  | —        | Internal note                                         |
| `expiration_days`         | —        | Days until credit expires (leave blank for no expiry) |

#### VIP Tiers

{% hint style="info" %}
Tier actions require **Advanced plan or above**.
{% endhint %}

**Assign to Tier** — Assigns a customer directly to an exclusive VIP tier.

| Field                       | Required | Description                            |
| --------------------------- | -------- | -------------------------------------- |
| `customer_identifier`       | ✅        | Customer email or Shopify customer GID |
| `exclusive_tier_identifier` | ✅        | The tier's name or ID in Joy           |

**Unassign exclusive tier** — Returns customer to their points-based tier.

| Field                 | Required | Description                            |
| --------------------- | -------- | -------------------------------------- |
| `customer_identifier` | ✅        | Customer email or Shopify customer GID |

#### Coupons

**Reward coupon** — Generates a discount coupon from a reward program.

| Field                       | Required | Description                      |
| --------------------------- | -------- | -------------------------------- |
| `customer_id`               | ✅        | Shopify customer GID             |
| `reward_program_identifier` | ✅        | Reward program name or ID in Joy |
| `admin_note`                | —        | Internal note                    |

**Revoke coupon** — Voids a discount code and refunds any points spent.

| Field           | Required | Description              |
| --------------- | -------- | ------------------------ |
| `customer_id`   | ✅        | Shopify customer GID     |
| `discount_code` | ✅        | The exact code to revoke |
| `admin_note`    | —        | Internal note            |

#### Membership

**Join loyalty program** — Converts a guest to active member status.

| Field                 | Required                     | Description                |
| --------------------- | ---------------------------- | -------------------------- |
| `customer_id`         | ✅ (or `customer_identifier`) | Shopify customer GID       |
| `customer_identifier` | ✅ (or `customer_id`)         | Customer email, ID, or GID |

**Exclude from loyalty program** — Removes a customer from the program.

| Field                 | Required                     | Description                |
| --------------------- | ---------------------------- | -------------------------- |
| `customer_id`         | ✅ (or `customer_identifier`) | Shopify customer GID       |
| `customer_identifier` | ✅ (or `customer_id`)         | Customer email, ID, or GID |
| `reason`              | ✅                            | Reason for exclusion       |

#### Custom activity

**Trigger custom activity** — Fires a custom earning program inside Joy.

| Field         | Required | Description                               |
| ------------- | -------- | ----------------------------------------- |
| `action-key`  | ✅        | Action key from the custom program in Joy |
| `customer_id` | ✅        | Shopify customer GID                      |

{% hint style="info" %}
First create a **Custom program** in Joy > Earn points > Custom, then copy its action key into the Flow extension settings.
{% endhint %}

***

### Flow Templates

#### 1 — Birthday points + email (Klaviyo)

**Goal:** Give bonus points on a customer's birthday and send a personalised email.

```
Trigger: Customer's birthday
→ Action (Joy): Add point
   email: {{ customer.email }}
   point: 200
   reason: Birthday bonus
→ Action (Klaviyo): Send email
   To: Customer email
   Subject: Happy birthday, {{ event|lookup:'Customer first name' }}!
   Body variables:
     {{ event|lookup:'Customer email' }}
     {{ event|lookup:'Customer first name' }}
     {{ event|lookup:'Customer points' }}
     {{ event|lookup:'Discount code' }}
```

***

#### 2 — Point expiration reminder series

**Goal:** Warn customers before points expire with escalating urgency.

```
Trigger: 30 days before the point expiration date
→ Action (Klaviyo): Send email — "Your points expire in 30 days"
   {{ event|lookup:'Customer points expire' }} points expiring

Trigger: 7 days before the point expiration date
→ Action (Klaviyo): Send email — "Hurry — 7 days left"

Trigger: Upon point expiration
→ Action (Klaviyo): Send email — "Your points have expired"
```

***

#### 3 — VIP tier upgrade congratulations

**Goal:** Celebrate a tier upgrade with a bonus and email.

```
Trigger: VIP tier achieved
→ Action (Joy): Add point
   email: {{ customer.email }}
   point: 500
   reason: Welcome bonus — new tier
→ Action (Klaviyo): Send email
   {{ event|lookup:'Tier name' }}
   {{ event|lookup:'Customer points' }}
   {{ event|lookup:'Discount code' }}
```

***

#### 4 — Pre-demotion rescue

**Goal:** Motivate customers to spend before they lose their tier.

```
Trigger: 4-week Pre-Tier Demotion Reminder
→ Action (Klaviyo): Send email — "You're at risk of losing your tier"
   {{ event|lookup:'Customer first name' }}
   {{ event|lookup:'Customer points' }}

Trigger: 1-day Pre-Tier Demotion Reminder
→ Action (Klaviyo): Send email — "Last chance — tier demotion tomorrow"
```

***

#### 5 — Reward any review app

**Goal:** Give points when a customer submits a review in any app that supports Shopify Flow (Loox, Okendo, Stamped, Yotpo, etc.).

```
Trigger: [Review App] — Review submitted
→ Action (Joy): Add point
   email: {{ customer.email }}
   point: 50
   reason: Thanks for your review!
```

See the individual integration guides (linked from the parent page) for app-specific trigger names.

***

#### 6 — Auto-enrol new customers

**Goal:** Add customers to the loyalty program the moment they sign up.

```
Trigger: Customer created  (native Shopify trigger)
→ Action (Joy): Join loyalty program
   customer_id: {{ customer.id }}
```

***

#### 7 — Referral reward notification

**Goal:** Send the referrer a confirmation email when their friend's order is complete.

```
Trigger: Referral for friend complete
→ Action (Klaviyo): Send email
   To: {{ event|lookup:'Referrer email' }}
   Body variables:
     {{ event|lookup:'Customer first name' }}
     {{ event|lookup:'Referrer reward type' }}
     {{ event|lookup:'Referrer reward' }}
     {{ event|lookup:'Customer points' }}
```

***

### FAQ

#### Which plan do I need?

Essential and above. **Assign to Tier** and **Unassign exclusive tier** require **Advanced or above**.

#### Why is my action not running?

Make sure the integration toggle is **On** in Joy > Integrations > Shopify Flow. This is the most common cause of silent failures.

#### Klaviyo doesn't show a variable picker — what do I type?

Use `{{ event|lookup:'Property name' }}` for any property with spaces in its name (see the property tables above). For single-word or underscored names like `customer_id`, you can use `{{ event.customer_id }}`.

#### Can I use multiple Joy actions in one Flow?

Yes. You can chain Joy actions — for example, add points and send a coupon in the same automation.

#### The "Adjust store credit" action isn't available — why?

It requires an additional Shopify permission. Enable the integration in Joy and click **Grant access** in the blue banner that appears.

#### Can I test triggers without real events?

Use Shopify Flow's built-in **Run test** feature, or use the **Admin manual point adjustment** trigger as a safe sandbox since you control exactly when it fires.
