# Template: Shopify orders as referral sales

For shops not on the app: each paid Shopify order reported as a sale, from Make or n8n.

A template for Make or n8n that turns every paid Shopify order into a sale in
your referral program, credited to the partner whose link or discount code
brought the customer.

Most stores do not need it. [Bolt Claw's Shopify app](https://boltclaw.ai/docs/referral-shopify),
or the webhooks on the program's **Setup** tab (see
[Referrals with Shopify](https://boltclaw.ai/docs/referral-billing-shopify)), report the same sales
and their refunds and disputes too. Use this template when the
order should pass through an automation of your own first. **Run only one of
the three for a store:** each records an order under its own event id, so two
of them would count every sale twice.

## What it sends

For each order Shopify reports as paid, one
`POST /v1/referrals/conversions`:

```json
{
  "program_id": "<your program id>",
  "event": "sale",
  "event_id": "shopify:5432109876543",
  "customer": { "id": "7012345678901" },
  "referral": { "code": "jane-20", "discount_code": "JANE10" },
  "amount": 4990,
  "currency": "USD"
}
```

- **`event_id`** is `shopify:` and the order's id. Shopify may deliver an
  order more than once; the same `event_id` records it once.
- **The customer** is Shopify's customer id, or `order-<order id>` for an order
  with no customer.
- **The referral code** comes from the `?via=` Bolt Claw's links add to the
  landing page (Shopify keeps it in the order's `landing_site`), and the
  discount code is the order's first one. Either is enough to credit a partner;
  anything that is not a code's letters, digits and hyphens is left out.
- **The amount** is the order total in the currency's minor units: 49.90 USD is
  `4990`, 1500 JPY is `1500` (no decimals), 12.345 KWD is `12345` (three).
- **A test order** (Shopify's test payments, or a development store) is sent
  with `"test": true` and recorded as test data.

The n8n template also sends the order's time and the click id from the landing
page; Make's sends neither, so the sale is dated when it arrives.

## Before you start

- A key with the **Referral tracking** preset (`conversions:write` and nothing
  else), made under **Settings, Developers**.
- The program's id, on its **Setup** tab.

## In Make

1. Download `https://boltclaw.ai/referrals/templates/make/shopify-order-to-sale.json` and import it (**...** menu, **Import
   Blueprint**).
2. In the first module, **Add** a webhook. Under **Show advanced settings**, set
   **Get request headers** and **JSON pass-through** to **Yes**. Copy its
   address.
3. In Shopify admin: **Settings, Notifications, Webhooks, Create webhook**, the
   event **Order payment**, format JSON, and the address. At the bottom of that
   page Shopify shows the key its webhooks are signed with.
4. **Expected signature**: replace `PASTE_THE_SHOPIFY_WEBHOOK_SIGNING_KEY` with
   that key. Keep the quotes.
5. **Record the sale in Bolt Claw**: replace `bc_live_PASTE_YOUR_KEY` in the
   `Authorization` header with your key, and `PASTE_YOUR_PROGRAM_ID` in the body
   with the program's id.
6. Switch the scenario on.

The filter after the webhook lets an order through only when Shopify's
signature matches and the topic is `orders/paid`: anybody who finds the address
could otherwise send a made-up order and pay a partner for it.

## In n8n

1. Download `https://boltclaw.ai/referrals/templates/n8n/shopify-order-to-sale.json` and import it (**Import from File**).
2. **Shopify Trigger**: choose a Shopify **Access Token** credential (the
   store's subdomain, an Admin API access token that can read orders, and the
   app's secret key, which the trigger checks every delivery with). It
   subscribes to `orders/paid` itself when you publish the workflow.
3. **Build the sale**: replace `PASTE_YOUR_PROGRAM_ID` with the program's id.
4. **Record the sale**: a **Header Auth** credential, Name `Authorization`,
   Value `Bearer bc_live_...`.
5. Publish the workflow.

**No Shopify app token?** Apps made in Shopify's Dev Dashboard since January
2026 get tokens that last 24 hours, and the trigger needs its token when the
workflow is published. The workflow has a second entry for that: disable
**Shopify Trigger**, enable **Shopify webhook (no app)**, add an **Order
payment** webhook in Shopify admin (as in step 3 for Make) pointing at that
node's production address, and put the signing key Shopify shows in **Verify
Shopify signature** (or in an n8n Variable `SHOPIFY_WEBHOOK_KEY`).

## Test it

Place an order with Shopify's test payments. It arrives with `test` set, so the
sale is recorded as test data: credited to the program's **Test partner**,
never paid, never counted, and deleted with **Clear test data**. Check:

- the run in Make's history, or the execution in n8n, ending with a `201` from
  Bolt Claw;
- the sale on the program's conversions, marked **Test**.

When Shopify delivers the same order again, Bolt Claw answers `200` with
`duplicate: true` and nothing changes. Test with a real order paid with test
payments rather than Shopify's **Send test notification**: that sends a sample
order, and a sample not marked as a test would be recorded as a live sale.

## What it does not do

Refunds and disputes. Add a second scenario or workflow on Shopify's
`refunds/create`, sending each refund with its own `event_id` and the sale's
in `refund_of`:

```json
{
  "program_id": "<your program id>",
  "event": "refund",
  "event_id": "shopify-refund:1234567890",
  "refund_of": "shopify:5432109876543",
  "amount": 1000,
  "currency": "USD"
}
```

Or use the app or the Setup tab's webhooks, which handle both.

<!-- https://boltclaw.ai/docs/referral-template-shopify-order as markdown. Generated from openapi.yaml; API version 1.22.0. -->
<!-- Every /docs page answers as markdown: add .md to its path, or send Accept: text/markdown. -->
