# Shopify Integration

The Gamopanda Shopify app adds three **Shopify Flow actions** and a **theme block** to your store. Flow actions let you trigger streak and challenge progress from any Shopify automation — order paid, checkout completed, loyalty event — without writing backend code. The theme block embeds the Gamopanda loyalty widget directly into your storefront, surfacing progress and rewards to logged-in customers in real time.

---

## Installation

Install the Gamopanda app from the Shopify App Store. Once installed, the Flow actions are immediately available in Shopify Flow and the theme block is available in your theme editor.

:::info
After installation, the app will store your `account_id` in a shop metafield (`gamopanda.account_id`) and `organization_id` in a shop metafield (`gamopanda.organization_id`). This is used automatically by the storefront widget — you do not need to configure it manually.
:::

---

## Floating widget

The Gamopanda **Storefront Script** is a theme block that embeds the loyalty widget into your storefront. It handles customer authentication automatically and renders the floating widget on every page where it is active.

### Adding the block to your theme

1. In your Shopify admin, go to **Online Store → Themes → Edit Theme**.
2. In the theme editor, open **App embeds**.
3. Find **Storefront Script** in the Gamopanda app blocks.
4. Configure the widget (see [Settings](#widget-settings) below).
5. Enable the **Storefront Script**
6. Save your theme.

#### Storefront Script block configuration

![Storefront Script block in the Shopify theme editor showing Template Id, Theme Id, and Floating Widget Id fields](/shopify-storefront-script-configuration.png)

---

### Widget settings

Configure the widget appearance and behaviour by entering the IDs from your Gamopanda dashboard:

| Setting | Description |
|---|---|
| **Template Id** | Controls the widget's copy and localisation. Find this in **Gamopanda → Templates**. See [Template](/template) for field details. |
| **Theme Id** | Controls the widget's colours and typography. Find this in **Gamopanda → Themes**. See [Theme](/theme) for field details. |
| **Floating Widget Id** | Controls the launcher button style and position. Find this in **Gamopanda → Floating Widgets**. See [Floating Widget](/floating_widget) for field details. |

All three fields are compulsory.

---

### How authentication works

The storefront block detects whether a customer is logged in and handles authentication accordingly:

**Logged-in customers**
The block calls the Gamopanda API server-side and fetches the user `accessToken`. The widget is initialised with the `accessToken`, giving the customer full access to their progress, milestones, and rewards.

**Guest visitors**
If no customer is logged in, the widget is initialised without an `accessToken`. The widget renders in guest mode — public content (e.g. how the programme works, available streaks and challenges) is visible, but personal progress is not shown until the customer logs in.

The locale of the storefront (`request.locale.iso_code`) is passed automatically — no extra configuration needed for multilingual stores.

---

### Rendered widget

#### Floating widget on storefront
![Floating Widget on Storefront](/floating-widget.png)

#### End User Display on storefront (logged-in customer)
![Logged In End User Display on Storefront](/loggedin-eud.png)

#### End User Display on storefront (guest visitor)
![Logged Out End User Display on Storefront](/loggedout-eud.png)

---

## Flow actions

:::note
Not on Shopify Plus?
The Flow actions below are custom app extensions that require Shopify Plus on some plans. If you're on a standard Shopify plan, you can achieve the same result using Flow's built-in **HTTP Request** action. [Jump to the HTTP Request guide](#using-http-request-in-flow-non-shopify-plus).
:::

### Execute Streak

**Logs a customer activity event that contributes to a streak.** Use this action in any Flow that tracks repeating behaviour — daily purchases, weekly visits, monthly workouts.

Internally, this action calls `POST /schema/streak_log/record` on your customer's behalf. See [Streak Logs](/streak-log) for field details.

#### Action fields

| Field | Required | Description |
|---|---|---|
| Customer | ✅ | The Shopify customer performing the activity. Resolved to a Gamopanda member automatically. |
| Streak Id | ✅ | The ID of the Gamopanda streak to log against. Found in your Gamopanda dashboard. |
| Activity Id | ✅ | The type of activity — e.g. `order_paid`, `visited_store`. |
| Activity Value | ✅ | The numeric value of the activity. Use `1` for `count` streaks. For `sum` streaks, pass the relevant value (e.g. order total). |
| Activity At | ✅ | The datetime the activity occurred. Used to determine the aggregation period. |
| Unique Identifier | The idempotency key so that duplicate requests are rejected. |

#### Action output

The action returns the created `StreakLog` record along with `streakProgress`, `achievedMilestone`(if any), `nextMilestone`(if any), `taskProgress` for the current period and `achievedMilestoneRewardLog`. You can use these output fields in downstream Flow steps. See [Streak Logs](/streak-log) for field details.

:::tip
Use the `achievedMilestoneRewardLog.id` output to chain directly into the **Update Milestone Reward Log with Coupon** action — no extra lookup needed.
:::

#### Execute Streak Flow Action
![Execute Streak Flow Action](/execute-streak-flow-action.png)

---

### Execute Challenge

**Logs a customer activity event that contributes to a challenge.** Use this action to track cumulative progress toward a spend, visit, or activity target — for example, a monthly $500 spend challenge.

Internally, this action calls `POST /schema/challenge_log/record` on your customer's behalf. See [Challenge Logs](/challenge-log) for field details.

#### Action fields

| Field | Required | Description |
|---|---|---|
| Customer | ✅ | The Shopify customer performing the activity. Resolved to a Gamopanda member automatically. |
| Challenge Id | ✅ | The ID of the Gamopanda challenge to log against. Found in your Gamopanda dashboard. |
| Activity Id | ✅ | The type of activity — e.g. `order_paid`, `order_created`. |
| Activity Value | ✅ | The numeric value of the activity. Use `1` for `count` challenges. For `sum` challenges, pass the spend amount, step count, or other measurable value. |
| Activity At | ✅ | The datetime the activity occurred. |
| Unique Identifier | The idempotency key so that duplicate requests are rejected. |

#### Action output

The action returns the created `ChallengeLog` record along with `challengeProgress`, `achievedMilestone`(if any), `nextMilestone`(if any) for the current period and `achievedMilestoneRewardLog`. You can use these output fields in downstream Flow steps. See [Challenge Logs](/challenge-log) for field details.

:::tip
Connect the `achievedMilestoneRewardLog.id` output directly to the **Update Milestone Reward Log with Coupon** action to issue a coupon in the same Flow, with no additional API calls.
:::

#### Execute Challenge Flow Action
![Execute Challenge Flow Action](/execute-challenge-flow-action.png)


---

### Update Milestone Reward Log with Coupon

**Stamps a coupon code and issuance timestamps onto a Reward Log.** Use this action immediately after **Execute Streak** or **Execute Challenge** detects a milestone crossing — it fulfils the reward by writing the coupon code back to the Reward Log record.

#### Action fields

| Field | Required | Description |
|---|---|---|
| Customer | ✅ | The Shopify customer who earned the reward. |
| Reward Log Id | ✅ | The ID of the Reward Log to update. Use the `achievedMilestoneRewardLog.id` output from **Execute Streak** or **Execute Challenge**. |
| Coupon Code | ✅ | The discount code issued to the customer. Generate this via Shopify's built-in discount actions before this step. |
| Reward Issued At | ✅ | The datetime the reward was issued. |
| Reward Expiry At | ✅ | The datetime the reward expires. |

#### Typical Flow pattern

```
Trigger: Order paid
  → Execute Streak / Execute Challenge
    → Condition: achievedMilestoneRewardLog.id is not empty
      → Create Discount Code (Shopify native)
        → Update Milestone Reward Log with Coupon
```

#### Update Milestone Reward Log with Coupon Flow Action
![Update Milestone Reward Log with Coupon Flow Action](/update-milestone-reward-log.png)

---

## Sample Flow templates

Copy and paste any of the Flow templates below directly into Shopify Flow using **Import** → **Flow File**.

---

### Execute Streak on order paid

Logs an order-paid activity against a streak whenever a customer completes a purchase. Replace `your-streak-id` with the Streak ID from your Gamopanda dashboard.
```json
4eea22c20f3741f559b9dd2a9bd4d5257a0d40e9baef447f847dc862e362de63:{"__metadata":{"version":0.1},"root":{"steps":[{"step_id":"01KNMQVD0CDVANPT6BK7WWKWDW","step_position":[0,0],"config_field_values":[],"task_id":"shopify::admin::order_paid","task_version":"0.1","task_type":"TRIGGER","description":null,"note":null,"name":null},{"step_id":"01KNNT4SG4EGFKM5F37CYYT3EZ","step_position":[0,280],"config_field_values":[{"config_field_id":"condition","value":"{\"uuid\":\"01KPAF07525PHTCAKA7TN3ZFQP\",\"lhs\":{\"uuid\":\"01KNNT4WMN5R57NXSBG1HP65VF\",\"parent_uuid\":\"01KPAF07525PHTCAKA7TN3ZFQP\",\"lhs\":{\"uuid\":\"01KNNT54HMP9HT0GTKD21RRWD7\",\"parent_uuid\":\"01KNNT4WMN5R57NXSBG1HP65VF\",\"value\":\"executeStreak.achievedMilestoneRewardLog.id\",\"comparison_value_type\":\"EnvironmentValue\",\"full_environment_path\":\"executeStreak.achievedMilestoneRewardLog.id\"},\"rhs\":{\"uuid\":\"01KNNT54HMQN30F3D84C2TXQF4\",\"parent_uuid\":\"01KNNT4WMN5R57NXSBG1HP65VF\",\"value\":\"\",\"comparison_value_type\":\"LiteralValue\"},\"value_type\":\"EnvironmentScalarDefinition:ID\",\"operator\":\"not_empty_and_not_nil?\",\"operation_type\":\"Comparison\"},\"operator\":\"AND\",\"operation_type\":\"LogicalExpression\"}"}],"task_id":"shopify::flow::condition","task_version":"0.1","task_type":"CONDITION","description":null,"note":null,"name":null},{"step_id":"01KNNT6D38EADEDS61P2VCPBMH","step_position":[-120,520],"config_field_values":[{"config_field_id":"api_call","value":"{\"name\":\"discountCodeBasicCreate\",\"blob\":\"{\\n  \\\"basicCodeDiscount\\\": {\\n    \\\"combinesWith\\\": {\\n      \\\"orderDiscounts\\\": true\\n    },\\n    \\\"title\\\": \\\"Discount Code\\\",\\n    \\\"startsAt\\\": \\\"{{ 'now' | date: '%Y-%m-%dT%H:%M:%SZ' }}\\\",\\n    \\\"endsAt\\\": \\\"{{ 'now' | date: '%s' | plus: 2592000 | date: '%Y-%m-%dT%H:%M:%SZ' }}\\\",\\n    \\\"appliesOncePerCustomer\\\": true,\\n    \\\"code\\\": \\\"GP-{{ 'now' | date: '%N' | append: order.customer.id | sha256 | slice: 0, 6 | upcase }}\\\",\\n    \\\"usageLimit\\\": 1,\\n    \\\"context\\\": {\\n      \\\"customers\\\": {\\n        \\\"add\\\": [\\\"{{ order.customer.id }}\\\"]\\n      }\\n    },\\n    \\\"minimumRequirement\\\": {\\n      \\\"subtotal\\\": {\\n        \\\"greaterThanOrEqualToSubtotal\\\": \\\"100\\\"\\n      }\\n    },\\n    \\\"customerGets\\\": {\\n      \\\"value\\\": {\\n        \\\"discountAmount\\\": {\\n          \\\"amount\\\": \\\"{% if executeStreak.achievedMilestone.milestoneTargetValue == 3 %}20.00{% else %}10.00{% endif %}\\\",\\n          \\\"appliesOnEachItem\\\": false\\n        }\\n      },\\n      \\\"items\\\": {\\n        \\\"all\\\": true\\n      }\\n    }\\n  }\\n}\\n\"}"}],"task_id":"shopify::admin::admin_api_operation","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":"Send Admin API request"},{"step_id":"01KP5GP045Y92XAKFZR8WTXDVR","step_position":[0,160],"config_field_values":[{"config_field_id":"customer_id","value":"{\"value\":\"\",\"default_value\":\"order.customer.id\"}"},{"config_field_id":"streakId","value":"your-streak-id"},{"config_field_id":"activityValue","value":"{{order.currentSubtotalPriceSet.shopMoney.amount}}"},{"config_field_id":"activityId","value":"order_paid"},{"config_field_id":"activityAt","value":"{{order.processedAt}}"},{"config_field_id":"uniqueIdentifier","value":"your-streak-id_{{order.id}}"}],"task_id":"019c4790-061b-79b3-a0aa-96ee7e916a4d","task_version":"1.0","task_type":"ACTION","description":null,"note":null,"name":"Execute Streak"},{"step_id":"01KP5GSDCQ763WZCV4MTY4EGQK","step_position":[-120,680],"config_field_values":[{"config_field_id":"customer_id","value":"{\"value\":\"\",\"default_value\":\"order.customer.id\"}"},{"config_field_id":"id","value":"{{executeStreak.achievedMilestoneRewardLog.id}}"},{"config_field_id":"couponCode","value":"{% for codes_item in sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.codes %}{{codes_item.code}}{% endfor %}"},{"config_field_id":"rewardIssuedAt","value":"{{sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.createdAt}}"},{"config_field_id":"rewardExpiryAt","value":"{{sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.endsAt}}"}],"task_id":"019d7e6b-5362-7697-b285-20f70f1abe80","task_version":"1.0","task_type":"ACTION","description":null,"note":null,"name":"Update Milestone Reward Log with Coupon"}],"links":[{"from_step_id":"01KNMQVD0CDVANPT6BK7WWKWDW","from_port_id":"output","to_step_id":"01KP5GP045Y92XAKFZR8WTXDVR","to_port_id":"input"},{"from_step_id":"01KP5GP045Y92XAKFZR8WTXDVR","from_port_id":"output","to_step_id":"01KNNT4SG4EGFKM5F37CYYT3EZ","to_port_id":"input"},{"from_step_id":"01KNNT6D38EADEDS61P2VCPBMH","from_port_id":"output","to_step_id":"01KP5GSDCQ763WZCV4MTY4EGQK","to_port_id":"input"},{"from_step_id":"01KNNT4SG4EGFKM5F37CYYT3EZ","from_port_id":"true","to_step_id":"01KNNT6D38EADEDS61P2VCPBMH","to_port_id":"input"}],"patched_fields":[],"variables":[],"note":null,"vertical_layout_enabled":true,"workflow_name":"3 day $100 purchase streak"}}
```
---

### Execute Challenge on order paid

Logs an order-paid activity against a challenge whenever a customer completes a purchase. Replace `your-challenge-id` with the Challenge ID from your Gamopanda dashboard.
```json
25c27b0340a09a71529dabbb48750b602d2ac5c1e5eb548ef9280c82a784ea2e:{"__metadata":{"version":0.1},"root":{"steps":[{"step_id":"01KNMQVD0CDVANPT6BK7WWKWDW","step_position":[0,0],"config_field_values":[],"task_id":"shopify::admin::order_paid","task_version":"0.1","task_type":"TRIGGER","description":null,"note":null,"name":null},{"step_id":"01KNNT4SG4EGFKM5F37CYYT3EZ","step_position":[0,280],"config_field_values":[{"config_field_id":"condition","value":"{\"uuid\":\"01KNNT54HMVPEYP9P843MA487T\",\"lhs\":{\"uuid\":\"01KNNT4WMN5R57NXSBG1HP65VF\",\"parent_uuid\":\"01KNNT54HMVPEYP9P843MA487T\",\"lhs\":{\"uuid\":\"01KNNV6GM4MR24TQNJFGZ5M99X\",\"parent_uuid\":\"01KNNT4WMN5R57NXSBG1HP65VF\",\"value\":\"executeChallenge.achievedMilestoneRewardLog.id\",\"comparison_value_type\":\"EnvironmentValue\",\"full_environment_path\":\"executeChallenge.achievedMilestoneRewardLog.id\"},\"rhs\":{\"uuid\":\"01KNNV6GM4FCDVK7H03KPETNJY\",\"parent_uuid\":\"01KNNT4WMN5R57NXSBG1HP65VF\",\"value\":\"\",\"comparison_value_type\":\"LiteralValue\"},\"value_type\":\"EnvironmentScalarDefinition:ID\",\"operator\":\"not_empty_and_not_nil?\",\"operation_type\":\"Comparison\"},\"operator\":\"AND\",\"operation_type\":\"LogicalExpression\"}"}],"task_id":"shopify::flow::condition","task_version":"0.1","task_type":"CONDITION","description":null,"note":null,"name":null},{"step_id":"01KNNT6D38EADEDS61P2VCPBMH","step_position":[-160,460],"config_field_values":[{"config_field_id":"api_call","value":"{\"name\":\"discountCodeBasicCreate\",\"blob\":\"{\\n  \\\"basicCodeDiscount\\\": {\\n    \\\"combinesWith\\\": {\\n      \\\"orderDiscounts\\\": true\\n    },\\n    \\\"title\\\": \\\"Discount Code\\\",\\n    \\\"startsAt\\\": \\\"{{ \\\"now\\\" | date: \\\"%Y-%m-%dT%H:%M:%SZ\\\" }}\\\",\\n    \\\"endsAt\\\": \\\"{{ \\\"now\\\" | date_plus: \\\"30 days\\\" | date: \\\"%Y-%m-%dT%H:%M:%SZ\\\" }}\\\",\\n    \\\"appliesOncePerCustomer\\\": true,\\n    \\\"code\\\": \\\"GP-{{ \\\"now\\\" | date: \\\"%N\\\" | append: order.customer.id | sha256 | slice: 0, 6 | upcase }}\\\",\\n    \\\"usageLimit\\\": 1,\\n    \\\"context\\\": {\\n      \\\"customers\\\": {\\n        \\\"add\\\": [\\\"{{ order.customer.id }}\\\"]\\n      }\\n    },\\n    \\\"minimumRequirement\\\": {\\n      \\\"subtotal\\\": {\\n        \\\"greaterThanOrEqualToSubtotal\\\": \\\"100\\\"\\n      }\\n    },\\n    \\\"customerGets\\\": {\\n      \\\"value\\\": {\\n        \\\"discountAmount\\\": {\\n          \\\"amount\\\": \\\"100.00\\\",\\n          \\\"appliesOnEachItem\\\": false\\n        }\\n      },\\n      \\\"items\\\": {\\n        \\\"all\\\": true\\n      }\\n    }\\n  }\\n}\"}"}],"task_id":"shopify::admin::admin_api_operation","task_version":"0.1","task_type":"ACTION","description":null,"note":null,"name":"Send Admin API request"},{"step_id":"01KP5GW3W43K3W3W1K1RDZ2QB3","step_position":[0,180],"config_field_values":[{"config_field_id":"customer_id","value":"{\"value\":\"\",\"default_value\":\"order.customer.id\"}"},{"config_field_id":"challengeId","value":"your-challenge-id"},{"config_field_id":"activityValue","value":"{{order.currentSubtotalPriceSet.shopMoney.amount}}"},{"config_field_id":"activityId","value":"order_paid"},{"config_field_id":"activityAt","value":"{{order.processedAt}}"},{"config_field_id":"uniqueIdentifier","value":"your-challenge-id_{{order.id}}"}],"task_id":"019d7e6b-5362-77aa-9b78-843ab9f512f2","task_version":"1.0","task_type":"ACTION","description":null,"note":null,"name":"Execute Challenge"},{"step_id":"01KP5GYX1P9ZRVM4E5QBBA1FXX","step_position":[-160,620],"config_field_values":[{"config_field_id":"customer_id","value":"{\"value\":\"\",\"default_value\":\"order.customer.id\"}"},{"config_field_id":"id","value":"{{executeChallenge.achievedMilestoneRewardLog.id}}"},{"config_field_id":"couponCode","value":"{% for codes_item in sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.codes %}{{codes_item.code}}{% endfor %}"},{"config_field_id":"rewardIssuedAt","value":"{{sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.createdAt}}"},{"config_field_id":"rewardExpiryAt","value":"{{sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.endsAt}}"}],"task_id":"019d7e6b-5362-7697-b285-20f70f1abe80","task_version":"1.0","task_type":"ACTION","description":null,"note":null,"name":"Update Milestone Reward Log with Coupon"}],"links":[{"from_step_id":"01KNNT4SG4EGFKM5F37CYYT3EZ","from_port_id":"true","to_step_id":"01KNNT6D38EADEDS61P2VCPBMH","to_port_id":"input"},{"from_step_id":"01KNMQVD0CDVANPT6BK7WWKWDW","from_port_id":"output","to_step_id":"01KP5GW3W43K3W3W1K1RDZ2QB3","to_port_id":"input"},{"from_step_id":"01KP5GW3W43K3W3W1K1RDZ2QB3","from_port_id":"output","to_step_id":"01KNNT4SG4EGFKM5F37CYYT3EZ","to_port_id":"input"},{"from_step_id":"01KNNT6D38EADEDS61P2VCPBMH","from_port_id":"output","to_step_id":"01KP5GYX1P9ZRVM4E5QBBA1FXX","to_port_id":"input"}],"patched_fields":[],"variables":[],"note":null,"vertical_layout_enabled":true,"workflow_name":"$1000 monthly purchase challenge"}}
```

## Using HTTP Request in Flow (non-Shopify Plus)

The Gamopanda Flow actions above are **custom app extensions** — on some Shopify plans these require Shopify Plus. If your store is on a standard plan and cannot use custom app actions, you can replicate the same behaviour using Shopify Flow's built-in **HTTP Request** action to call the Gamopanda API directly.

:::info
The HTTP Request action is available on all Shopify plans that include Flow. You will need your Gamopanda `x-api-key` and `x-api-secret` to authenticate requests.
:::

---

### Logging a streak activity

Use the **HTTP Request** action to call `POST /schema/streak_log/record`. See [Streak Logs](/streak-log) for the full list of fields, required parameters, and response structure.

**HTTP Request configuration:**

| Setting | Value |
|---|---|
| URL | `/api/v1.0/schema/streak_log/record` |
| Method | `POST` |
| Headers | `x-api-key: <your-api-key>` · `x-api-secret: <your-api-secret>` · `Content-Type: application/json` |

**Request body** (map Flow variables to these fields):

```json
{
  "streakId": "your-streak-id",
  "ownedBy": {
    "externalId": "{{ order.customer.id }}"
  },
  "activityId": "order_paid",
  "uniqueIdentifier": "your-streak-id_{{ order.id }}",
  "activityAt": "{{order.processedAt}}",
  "activityValue": "{{order.currentSubtotalPriceSet.shopMoney.amount}}",
  "status": "live"
}
```

See [Streak Logs](/streak-log) for the full field reference and response details, including how to read `achievedMilestoneRewardLog` from the response to chain into a coupon update step.

:::tip
Check `achievedMilestoneRewardLog.id` in the HTTP response body. If it is not empty, a milestone was just crossed — use it as the `Reward Log Id` in a follow-up **HTTP Request** to [update the reward log with a coupon](#updating-a-reward-log-with-a-coupon).
:::

Use the **HTTP Request** action to call `POST /schema/challenge_log/record`. See [Challenge Logs](/challenge-log) for the full list of fields, required parameters, and response structure.

**HTTP Request configuration:**

| Setting | Value |
|---|---|
| URL | `/api/v1.0/schema/challenge_log/record` |
| Method | `POST` |
| Headers | `x-api-key: <your-api-key>` · `x-api-secret: <your-api-secret>` · `Content-Type: application/json` |

**Request body** (map Flow variables to these fields):

```json
{
  "challengeId": "your-challenge-id",
  "ownedBy": {
    "externalId": "{{ order.customer.id }}"
  },
  "activityId": "order_paid",
  "uniqueIdentifier": "your-streak-id_{{ order.id }}",
  "activityAt": "{{order.processedAt}}",
  "activityValue": "{{order.currentSubtotalPriceSet.shopMoney.amount}}",
  "status": "live"
}
```

See [Challenge Logs](/challenge-log) for the full field reference and response details, including how to read `achievedMilestoneRewardLog` from the response to trigger a reward.

:::tip
Check `achievedMilestoneRewardLog.id` in the HTTP response body. If it is not empty, a milestone was just crossed — use it as the `Reward Log Id` in a follow-up **HTTP Request** to [update the reward log with a coupon](#updating-a-reward-log-with-a-coupon).
:::

Once a milestone is crossed (detected from the `achievedMilestoneRewardLog` in the streak or challenge log response), use a second **HTTP Request** action to stamp the coupon. See [Reward Log](/reward_log) for field details.

**HTTP Request configuration:**

| Setting | Value |
|---|---|
| URL | `/api/v1.0/schema/reward_log/record/{{ achievedMilestoneRewardLog.id }}` |
| Method | `PATCH` |
| Headers | `x-api-key: <your-api-key>` · `x-api-secret: <your-api-secret>` · `Content-Type: application/json` |

**Request body:**

```json
{
  "couponCode": "{% for codes_item in sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.codes %}{{codes_item.code}}{% endfor %}",
  "rewardIssuedAt": "{{sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.createdAt}}",
  "rewardExpiryAt": "{{sendAdminApiRequest.codeDiscountNode.codeDiscount.DiscountCodeBasic.endsAt}}"
}
```

See [Reward Log](/reward_log) for the full field reference

#### Typical HTTP Request chain

```
Trigger: Order paid
  → HTTP Request: POST streak_log / challenge_log
    → Condition: body.achievedMilestoneRewardLog.id is not empty
      → Create Discount Code (Shopify native)
        → HTTP Request: PATCH reward_log with coupon
          → Send email to customer with coupon
```

| Resource | Description |
|---|---|
| [Streak](/streak) | Configure the streaks your Flow actions log against |
| [Challenge](/challenge) | Configure the challenges your Flow actions log against |
| [Milestone](/milestone) | Reward checkpoints that trigger the reward log |
| [Reward Log](/reward_log) | The reward record updated by **Update Milestone Reward Log with Coupon** |
| [Template](/template) | Widget copy and localisation settings |
| [Theme](/theme) | Widget visual styling |
| [Floating Widget](/floating_widget) | Launcher button configuration |
