# Purple Dot Overview

### [What is Purple Dot?](#what-is-purple-dot) <a href="#what-is-purple-dot" id="what-is-purple-dot"></a>

Purple Dot is a pre-order management platform. It enables you to easily sell stock before it arrives through creating pre-order experiences.&#x20;

Purple Dot provides all the tooling required to manage pre-orders including the customer experience (display components), transacting the customer (payments, including 100% pay upfront, split payment with a deposit upfront and rest on ship, or full charge on ship) customer service flows (customer self-service, with internal dashboards and integrations), communications (email) and data (as events, visualizations and downloads).

To set-up a product a pre-order, a Waitlist is created that takes an item from your existing catalog, adds estimated ship dates as a date range along with the number of units you want to pre-sell by SKU or total. Purple Dot then enables customers to pre-order this product (checking out), the pre-order wait experience (self-serve amend, cancel and email updates), and the transition of pre-orders to regular orders when the product arrives in your warehouse.

### [Why use Purple Dot for pre-orders?](#what-is-purple-dot) <a href="#what-is-purple-dot" id="what-is-purple-dot"></a>

We are the only pre-order solution that is&#x20;

* fully FTC compliant in charging upfront for pre-orders
* compatible with all major downstream 3PL and warehouse / shopping partners
* always keeps the customer up to date on where their pre-order is at

A small amount of engineering effort is required to get started, and the integration can be done by you or by Purple Dot. See our [Getting Started Guide](/docs/getting-started).

Pricing is a flat all-in % transaction fee, depending on your country and with additional volume discounts available. **This includes all payment processing fees.** There are no additional payment or transaction fees from your eCommerce platform since Purple Dot is transacting the pre-order instead of your eCommerce platform.

#### [How does Purple Dot work?](#feature-comparison) <a href="#feature-comparison" id="feature-comparison"></a>

Once you're up and running with Purple Dot, we automatically adjust your customers' online shopping experience to provide the 3 core value props listed above:

|                              | As separate checkout                                                                                                                                                                                                                                                                                                                                                                                                                                                   | As payment provider (Shopify Plus only)                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Visual changes in your store | <p>For products that have a Waitlist, a Pre-order button with estimated delivery dates replaces your regular Add to Cart button.<br><br>Sold Out labels for these products are removed.</p>                                                                                                                                                                                                                                                                            | Same.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Checkout flow                | <p>Clicking the Pre-order button leads into <strong>a new checkout flow</strong>, that mirrors your brand’s look, feel and existing checkout functionality. <br><br>This separate checkout is what enables pre-orders to be held outside your system until stock arrives, and the FTC compliant payment flow for pre-orders.<br><br>Supports single-item, multi-item, and mixed cart flows (where the customer's cart contains both in-stock and pre-order items).</p> | <p>Clicking the Pre-order button leads into <strong>your existing checkout flow</strong>.<br><br>To provide FTC compliant payment flow for pre-orders, Purple Dot will be the only payment option available when customer is buying a pre-order.</p>                                                                                                                                                                                                                                         |
| Emails                       | **Pre-order post-purchase transactional emails**, including: confirmation, updated shipping dates, amended or canceled order.                                                                                                                                                                                                                                                                                                                                          | Same.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Customer payment             | <p><strong>You can choose</strong> to charge the customer in full at checkout, some upfront and the rest later, or all later.</p><p></p><p><strong>Funds are held</strong> until pre-orders are exported as ready to fulfil, which enables an FTC compliant payment flow for pre-orders. Customers can cancel for a full refund anytime before ship. See <em>Cancellations.</em><br><br>There is an option to release the funds early for an extra charge.</p>         | <p>Customer is always charged in full at checkout. </p><p></p><p>Otherwise same.</p>                                                                                                                                                                                                                                                                                                                                                                                                         |
| Pre-order tracking           | **Pre-orders are held in Purple Dot until you are ready to fulfil** (typically when the product(s) arrive at your warehouse), at which point they are exported to your e-commerce platform and fulfilled as regular orders.                                                                                                                                                                                                                                            | <p>An order with "On Hold" against the pre-order line item is <strong>created in Shopify as soon as the checkout completes</strong>.<br><br>Once stock arrives and you are ready to fulfil, <strong>you can remove this fulfilment hold in Purple Dot or your Shopify portal</strong>.<br><br>Some ERP/3PL do not support these Shopify "On Hold"s - in those cases we integrate with the ERP/3PL directly to ensure only pre-orders that are ready to fulfil flow down to your ERP/3PL.</p> |
| Cancellations                | Pre-order cancellations can be **facilitated by the customer via the Purple Dot self-serve embedded in your site or  the Purple Dot** [**self-service pre-order management page**](https://www.getpurpledot.com/shopper) **or by you via your Purple Dot Merchant Portal**, at any point before the pre-order is ready to fulfil.                                                                                                                                      | Same.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Refunds                      | <p>Refunds for returned pre-orders are <strong>processed by Purple Dot</strong>, and can be issued from the Purple Dot Merchant Portal.<br><br>Optionally, refunds can also be triggered automatically based on events from your e-commerce platform delivered as webhooks.</p>                                                                                                                                                                                        | Same.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Analytics                    | **Purple Dot integrates seamlessly with your analytics, advertising and CRM tracking libraries**. Events like conversions can be forwarded to any client library included on the page.                                                                                                                                                                                                                                                                                 | Same.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Shipping rates               | <p>Can use the same rate settings as your in-stock orders, or you <strong>can configure pre-order specific rates</strong>.<br><br>You can also choose to <strong>ship a pre-order and in-stock order together or separately, or let the customer choose</strong>.</p>                                                                                                                                                                                                  | Uses the same settings as your in-stock orders.                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| Cost                         | A % transaction fee depending on country and with volume discounts available. **This includes all payment processing fees.** [Contact](mailto:sales@getpurpledot.com) us for pricing.                                                                                                                                                                                                                                                                                  | Same.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |


# Getting Started

Start by signing up to Purple Dot as a Merchant. If you don't have a Merchant Account yet, send us an email at <sales@getpurpledot.com> and we'll get you set up.

Once you have your Purple Dot account, you can finish the rest of the setup:

1. **Sign in** to the [Merchant Portal](https://www.purpledotprice.com/merchant-portal) with your email. This is where you manage your Waitlists, pre-orders and configure the integration. You can also **add more team members** there.
2. **Connect Purple Dot** to your eCommerce store
   1. [Shopify](/docs/shopify-stores/install-our-app)
   2. [Salesforce](/docs/salesforce-stores/integrate-purple-dot-with-salesforce)
   3. [Other](/docs/other-e-comm-platforms/integrate-into-another-platform)
3. **Configure email styling, shipping rates and taxes** in your [Merchant Portal](https://www.purpledotprice.com/merchant-portal).
4. **Connect your bank account** to receive payouts from Purple Dot on your pre-order sales. To do this, use our Stripe onboarding flow in the Balance section of the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/finances).

Once you've completed those steps, you can [test your integration](/docs/shopify-stores/test-the-integration) and launch it!


# Install our app

You will be given a unique link to single-click install Purple Dot into your Shopify store.

The app is verified and approved by Shopify and distributed via the App Store, but it is not listed in the App Store as it is unique to your store.

The app will ask for certain permissions that allow Purple Dot to do what we need to be able to do

* stay in sync with your product catalog
* see and create customer data
* see and create orders

Please approve the required permissions and install the app.


# Integrate Purple Dot with your Storefront

### [Overview](#overview)

How you integrate Purple Dot into your storefront depends on how it is built:

* [Integrate into Shopify Themes built with Liquid](/docs/shopify-stores/integrate-purple-dot-with-your-storefront/integrate-into-shopify-themes-built-with-liquid)
* [Integrate into Shopify Headless Storefronts](/docs/shopify-stores/integrate-purple-dot-with-your-storefront/integrate-into-shopify-headless-storefronts)
* [Integrate into Shopify Hydrogen Storefronts](/docs/shopify-stores/integrate-purple-dot-with-your-storefront/integrate-into-shopify-hydrogen-storefronts)

### [Before you continue](#before-you-continue)

Having a product with some variant(s) on pre-order will make it easier to test each step from the integration guides above. You may re-use an exisiting product, or create a new one specifically for testing the Purple Dot integration:

#### [1. Create a test product](#1.-create-a-test-product) <a href="#id-1.-create-a-test-product" id="id-1.-create-a-test-product"></a>

* Go to your Shopify Admin page and go to the Products list page.
* Click Add Product
* Set the name of the product to `Z - Purple Dot Test Product` and make sure it is not added to any collections or tags to make it difficult for real shoppers to find
* Set the sales channels to Online Store only
* Give the product 3 Size options/variants
  * Small should be out of stock
  * Medium should have 1 unit of stock
  * Large should be out of stock
* Set the price of these variants to free just in case anybody does find it

#### [2. Set up its Waitlist](#2.-set-up-a-waitlist) <a href="#id-2.-set-up-a-waitlist" id="id-2.-set-up-a-waitlist"></a>

* Go to your Purple Dot [Merchant Portal](https://www.purpledotprice.com/merchant-portal), navigate to Waitlists and click New Waitlist
* Select the `Z - Purple Dot Test Product` you created earlier
* Pick any future ship dates
* Set up incoming pre-order stock
  * Small should be out of pre-order stock
  * Medium should have 1 unit of pre-order stock
  * Large should have 1 unit of pre-order stock
* Save the Waitlist

### [Testing the Integration](#testing-the-integration)

To check that everything is working correctly, look for the following

[**On the PDP**](#on-the-pdp)

Referencing the test product setup outlined earlier

* When the Small variant is selected, the product appears as out of stock and no pre-order messaging is shown.
* When the Medium variant is selected, the product appears as in stock and no pre-order messaging is shown. When added to cart, the standard Shopify checkout is used.
* The Large variant is selected, the CTA changes to "Pre-order" and the Waitlist ship dates are displayed underneath. When added to cart, the Purple Dot checkout is used (Combined, Separate or Express) and the expected ship dates are shown.

If using Express Checkout:

* The express checkout opens when the Pre-order button is clicked.

If using Separate Cart:

* The product is added to a dedicated pre-order cart and the pre-order cart button is now showing throughout the store.

If using Combined Cart:

* The Purple Dot checkout is used whenever you try to check out, from the /cart page and from any quick checkout links.

[**On the PLP**](#on-the-plp)

If you have any quick view components or modals, any Add to Cart functionality in those should work the same as on a PDP.

[**Extra testing if using Combined Cart**](#extra-testing-if-using-combined-cart)

To enable this checkout type, Purple Dot ticks "Continue selling when out of stock" for every product variant that is on pre-order. Our system ensures that no oversell can occur beyond the defined pre-order stock level but only if our Pre-order button shows in every instance where the shopper can add products to their cart. Please check that:

* In your Shopify store every product with a Live Waitlist has only the Online Store sales channel turned on
* Purple Dot's Pre-order button shows for size Large everywhere it is possible to add products to the cart
* Products on pre-order are excluded from any functionality that can automatically add products to the cart thereby bypassing Purple Dot (e.g. buy one get one free)
* If you have other apps in your Shopify store that also use 3rd party checkout you must disable these once the shopper's cart contains a line item on pre-order with Purple Dot. You can check for this by inspecting if any of the line items in the Shopify cart contains a `__releaseId` property.


# Integrate into Shopify Themes built with Liquid

#### [1. Enable Purple Dot in your theme](#id-1.-enable-purple-dot-in-your-theme)

Having completed [Install our app](/docs/shopify-stores/install-our-app)

1. Navigate to a theme where you wish to test Purple Dot
2. Click "Edit theme", then "App embeds" on the sidebar of the theme code editor
3. Search for "Purple Dot"
4. Provide the "Purple Dot API Key" and "Purple Dot Shared Secret" values that you can find at the bottom of the Integrations page in our [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations)
5. Enable the embed and save the theme

#### [2. Add the Shopper Portal](#id-6.-add-the-shopper-portal)

The shopper portal allows your customers to see their pre-order history and cancel pre-orders before they are fulfilled.&#x20;

We recommend hosting the shopper portal iframe on a new page - e.g. `/pages/manage-pre-orders` - that is linked from your support pages, similar to how a returns portal would be.

The title of the page should be **Manage Pre-orders.**

The following snippet should be placed on a Shopify page by editing the page's HTML:

```
<purple-dot-self-service />
```

#### [**3. Configure Separate Cart (optional)**](#id-3.-configure-separate-cart-optional)

If your preferred checkout method is to use a separate cart, there is some additional configuration required to place the separate cart icon and enable the variant selectors on liquid theme:

1. **Configure the cart placement**

```js
window.PurpleDotConfig = {
  ...
  cart: {
    // Icon styles
    fill: '#000000',
    strokeWidth: '1.5px',
    matchFill: '.icon--cart',
    width: '22px',
    height: '22px',
    // Function to place the cart element onto the page
    placeElement: (cartElement, cartLink) => {
      const cartLinkContainer = cartLink.parentElement;
      const pdCartContainer = cartLinkContainer.cloneNode();
      // Adjust these next two lines to your DOM, if necessary
      pdCartContainer.appendChild(cartElement);
      cartLinkContainer.insertAdjacentElement('beforebegin', pdCartContainer);
      // Returns the container element
      return pdCartContainer;
    },
  },
};
```

{% hint style="info" %}
**Unexpected DOM structure?**

Sometimes, you may find empty elements with padding/margin etc., if the theme you're working on is different to the one assumed in our previous example. If this is the case, you can set up a mutation observer on an ancestor of the cart icon like so:
{% endhint %}

```js
// Function to place the cart element onto the page
placeElement: (cartElement, cartLink) => {
  const cartLinkContainer = cartLink.parentElement;
  const pdCartContainer = cartLinkContainer.cloneNode();
  const nav = document.querySelector('nav.Header__SecondaryNav');
  // Define observer callback
  const observer = new MutationObserver(() => {
    const iframe = document.querySelector('iframe.purple-dot-frame');
    if (iframe.style.display === "none") {
      pdCartContainer.style.display = "none";
    } else {
      // May need to adjust this line to suit your theme
      pdCartContainer.style.display = "inline-block";
    }
  });
  // Adjust these next two lines to your DOM, if necessary
  pdCartContainer.appendChild(cartElement);
  cartLinkContainer.insertAdjacentElement('beforebegin', pdCartContainer);
  // Set up observer:
  // IMPORTANT: 'attributes' must be true, as iframe.style.display will change
  observer.observe(nav, { attributes: true, childList: true, subtree: true });
  // Returns the container element
  return pdCartContainer;
},
```

2. **Configure variant selectors on a PDP**

Sometimes, a PDP will have variant selectors that show the variant as sold out, even though the variant is available for preorder. In this case, we can target these elements, and remove a 'disabled' class (or similar) from them in order to 'enable' them.

There are two ways of selecting elements (depending on whether or not they are inside an ATC form), but you must always provide a class to remove.

```js
window.PurpleDotConfig = {
  ...
  pdp: {
    variantSelector: {
      // CSS selector to be queried for inside the ATC form
      selector: '.some-selector',
      // Find variant selector elements that are outside the ATC form
      find: () => document.querySelectorAll('.another-selector'),
      // Class to remove to enable the variant
      disabledClass: 'disabled',
    },
  },
};
```

<br>


# Minimum Theme Requirements

For Shopify merchants integrating Purple Dot into Shopify Themes built with Liquid, the theme must meet the 3 criteria below.&#x20;

If you need help, please contact [support](mailto:support@getpupledot.com).&#x20;

### Requirements

#### [1. Add to Cart Button with type="submit" (inside \<form>)](#1.-add-to-cart-button-with-type-submit-inside-less-than-form-greater-than)

Any button that is used to add products to the cart should have the type attribute set to `submit` and should also be inside the \<form> HTML element.

```html
<button type="submit">Add to Cart</button>
```

#### [2. Form Element with action="/cart/add"](#2.-form-element-with-action-cart-add)

Each of these buttons must be wrapped in a `<form>` element, with the action attribute set to `/cart/add`.

```html
<form action="/cart/add" method="post">
    <!-- Your Product form content goes here -->
</form>
```

#### [3. Variant selectors](#3.-variant-selectors)

Within the form, there should be an `input` or `select` element with the name attribute set to `id`. The value of this input element must be updated dynamically based on the current variant selected in the form. This ensures that Purple Dot can correctly identify the selected product variant.

```html
<input type="hidden" name="id" value="{{ variant.id }}"/>
```

Additional requirement for a `select` based implementation is that only the `option` of the variant the shopper had actually selected is `selected`.

```html
<select name="id">
  {% for variant in product.variants %}
    {% if variant.available %}
      <option
        {% if product.selected_variant.id == variant.id %}
          selected
        {% endif %}
        value="{{ variant.id }}">
        <...>
      </option>
    {% else %}
        <option 
          {% if product.selected_variant.id == variant.id %}
            selected
          {% endif %}
          disabled="disabled"
          value="{{ variant.id }}">
          <...>
        </option>
    {% endif %}
  {% endfor %}
</select>
```

### Test your PDP

Run this code in your console, when on a merchants PDP:

```javascript
const form = document.querySelector('form[action*="/cart/add"]');
const variantID = form?.querySelector('[name="id"]');
const button = form?.querySelector('button[type="submit"]');

console.log('form should exist -->', !!form);
console.log('form should contain an element identifying the product variant -->', !!variantID);
console.log('form should contain a submit button -->', !!button);
```


# Integrate into Shopify Headless Storefronts

## Headless integration overview

Purple Dot integrates with your existing storefront and enables you to create pre-order experiences. When integrating with a headless storefront Purple Dot, provides a set of components that can be used to build the integration.

Purple Dot supports a number of different checkout flows for headless stores:

* [**Combined**](https://docs.getpurpledot.com/docs/platform-integration-with-shopify/integrate-purple-dot-with-your-storefront/integrate-into-shopify-headless-storefronts/shopify-headless-combined-checkout)**:** This checkout method allows the shopper to add a pre-order item to their cart, but also continue shopping for other in-stock and pre-order items. When they are ready to checkout, they can be presented with a checkout that allows them to combine both pre-order and in-stock items at once, and choose to either ship them together or separately. This flow uses your store’s normal Shopify cart.
* [**Express**](https://docs.getpurpledot.com/docs/shopify-stores/integrate-purple-dot-with-your-storefront/integrate-into-shopify-headless-storefronts/shopify-headless-express-checkout): This checkout method presents a quick checkout modal to the shopper that opens directly when the Add to Cart button is clicked, so that the shopper can pre-order that single item right away. This flow (also referred to as “Separate Bag”) uses Purple Dot’s own cart, separate from your Shopify cart.

{% hint style="info" %}
If you are unsure which checkout flow your store is configured for, please reach out to Purple Dot Support to confirm, or to switch from one checkout method to another.
{% endhint %}

The integration requirements will differ slightly depending on which checkout method is chosen.


# Shopify Headless - Combined Checkout

## Combined checkout overview

The Combined Checkout flow uses your store’s normal Shopify cart, unlike the Express flow, which uses Purple Dot’s own cart. This means that pre-order and in-stock items coexist within the same Shopify cart, and Purple Dot’s integration layers on top of your existing cart implementation to manage pre-order metadata and checkout routing.

There are 5 key requirements an integration needs to implement for a Combined checkout:

* **Displaying pre-order items.** Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The integration needs to show that those items are on pre-order, with the estimated ship dates, the "Learn more” informational content and a “Pre-order” call to action.
* **Adding pre-order items to cart.** When adding an item to cart, the integration needs to determine if it is a pre-order, and attach the waitlist ID and ship dates if it is.
* **Showing pre-order items in cart.** When a pre-order item is in the cart, the estimated ship dates need to be displayed.
* **Using the Combined pre-order checkout.** The Purple Dot pre-order checkout lets shoppers checkout with pre-order items. When a pre-order item is in the cart, the integration needs to direct the shopper to the Purple Dot pre-order checkout instead of the Shopify checkout.
* **Shopper portal.** The shopper self-service portal lets shoppers manage their pre-orders. The integration needs to be embedded on a page in the storefront that the shoppers will be directed to in their confirmation email.

Purple Dot currently supports two types of carts:

* Shopify [AJAX API cart](https://shopify.dev/docs/api/ajax/reference/cart)
* Shopify [Storefront API cart](https://shopify.dev/docs/api/storefront/2023-07/queries/cart)

Some aspects of the integration differ depending on what cart is being used.

### Displaying pre-order items

Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The[ Pre-order availability API](#pre-order-availability-api) can be queried for the pre-order status of any product or variant on the store.

When a variant has an open waitlist, it will be set to “continue selling” in Shopify, and how it should be displayed is determined by the [Pre-order availability API](#pre-order-availability-api).

#### Product pages

Anywhere a product can be added to cart - on product pages, or collection pages and elsewhere with add to cart controls - the integration should use the variant's pre-order state provided by the [Pre-order availability API](#pre-order-availability-api) to determine how a variant should be treated. There are 4 possible states:

* `NO_WAITLISTS` state means the variant has no open waitlists and no changes need to be made.
* `AVAILABLE_IN_STOCK` state means the variant has an open waitlist but also has stock available in Shopify, and should be treated like a regular in-stock product.
* `ON_PREORDER` state means the variant has an open waitlist and no stock in Shopify and should be treated as a pre-order. The following should be shown:
  * Change the add to cart button label to “Pre-order”, if the button has a label.
  * Show the estimated ship dates. This is the `display_dispatch_date` as returned by the 2 [Pre-order availability API](#pre-order-availability-api) endpoints.
  * Show the [Learn more](#learn-more-component) component near the button.
* `SOLD_OUT` state means the variant has an open waitlist but no stock in Purple Dot or Shopify. The add to cart button must be disabled and the label should be changed to “Sold out”.

Whenever a new variant is selected, for example using a size or colour picker, the [Pre-order availability API](#pre-order-availability-api) state should be used to determine how to display the newly selected variant. For products with multiple variants, it is possible for some variants to be on pre-order while others are in-stock or sold out.

#### Collection pages

On collection pages and in any panels that list products, the integration may show a “Pre-order” label for products that are fully on pre-order, using the state provided by the product pre-order state endpoint. The possible states are the same as for a single variant, but take into account all of the product's variants, and are therefore suitable for cases where no variant is selected.

### Adding pre-order items to cart

Whenever a pre-order item is added to cart, two line item properties must be added to it:

* `__releaseId`, a hidden property whose value indicates which waitlist it's on. This is the `id` as returned by the 2 [Pre-order availability API](#pre-order-availability-api) endpoints.
* `Purple Dot Pre-order`, a property whose value has the estimated ship dates and that indicates that something is a pre-order. This is the `display_dispatch_date` as returned by the 2 [Pre-order availability API](#pre-order-availability-api) endpoints.

Whenever an item is added to cart from anywhere on the site, it's pre-order status needs to be checked, and properties added if it is in `ON_PREORDER` or `SOLD_OUT` state (nothing needs to be done if it is `NO_WAITLISTS` or `AVAILABLE_IN_STOCK`state).

If using the AJAX API cart, Purple Dot provides a pre-built component (see [below](#working-with-the-cart)) that can intercept all calls to the cart API and insert the required properties automatically.

If using the Storefront API, the integration must take care to always attach these properties when a pre-order item is added to cart.

### Showing pre-order items in cart

When displaying items in the side cart or on a cart page, the `Purple Dot Pre-order` line item property should always be displayed. It indicates that the item is a pre-order and its estimated ship dates.

Most storefronts already display the cart item properties, so this should happen automatically. If not, you need to make sure the property is shown in the side cart and on the cart page.

### Using the Combined pre-order checkout

In order to hold pre-orders outside your downstream systems and for FTC compliance, the mirrored Purple Dot pre-order checkout is used when the shopper is checking out with pre-order items in their card. When a pre-order item is in the cart, the integration needs to direct the shopper to the Purple Dot checkout instead of the Shopify checkout. Purple Dot provides a pre-built component for checking the cart state (see below), which can be used to conditionally change any links to the checkout.

The pre-order checkout can be opened on any page as an overlay iframe, or it can be hosted on the cart page and opened conditionally on load.

### Shopper portal

The shopper portal is an iframe that embeds a portal that lets shoppers manage their pre-orders. The integration must embed the shopper portal component on a dedicated page, so that shoppers can be linked to it from their confirmation emails.

## Components

Purple Dot provides a package that includes the components needed for the integration. It can be installed from `npm`, and must be included and initialised whenever the storefront is loaded.

```bash
npm install -S @purple-dot/browser
```

```jsx
import * as PurpleDot from '@purple-dot/browser';

PurpleDot.init({
  apiKey: 'xxx',
});
```

> 💡 Your API key can be found in the Merchant Portal under Settings > Integration.

When initialised, it will inject a `<script>` tag that loads additional code required to make Purple Dot work.

The package contains several modules structured like this:

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FNaWBrYziOxKecIsyif7e%2FScreenshot%202023-08-02%20at%2019.23.48.png?alt=media&amp;token=ffcb9b23-1a14-4964-9594-8875d266ed3a" alt=""><figcaption><p><code>@purple-dot/browser</code> structure</p></figcaption></figure>

### Pre-order availability API

The pre-order availability API should be used for determining if a product or a variant should be displayed as a pre-order and the estimated ship dates if so.

Purple Dot provides a client library that can be used like:

```jsx
import * as api from '@purple-dot/browser/api';

const variantResponse = await api.fetchVariantsPreorderState(variant.id);

const productResponse = await api.fetchProductsPreorderState(product.handle);
```

* `variantPreorderState` provides data on the pre-order state of any variant. It should be used when interacting with a specific variant, such as on a product page. It returns:
  * `state`, one of:
    * `NO_WAITLISTS` - the variant has no open waitlists and no pre-order related functionality should trigger
    * `AVAILABLE_IN_STOCK` - the variant is available in stock and should not be sold as a pre-order (even though there is an open waitlist)
    * `ON_PREORDER` - the variant is available as a pre-order only
    * `SOLD_OUT` - the variant is completely sold out, in stock and on pre-order
  * `waitlist`
    * `id` - the waitlist ID
    * `display_dispatch_date` - the estimated ship date to display for the variant if on pre-order
* `productPreorderState` provides data on the pre-order state of a whole product. It can be used in contexts where no variant is selected, such as on a collection page. It returns:
  * `state`, one of:
    * `NO_WAITLISTS` - the product has no open waitlists and no pre-order related functionality should trigger
    * `AVAILABLE_IN_STOCK` - the product has some variants available in stock, and should be displayed as a regular in-stock product
    * `ON_PREORDER` - the product has all variants available on pre-order, and should be displayed as a pre-order product
    * `SOLD_OUT` - the product is completely sold out
  * `waitlist`
    * `id` - the waitlist ID
    * `display_dispatch_date` - the estimated ship date to display for the product if on pre-order

### Learn more component

When a variant is on pre-order, the estimated ship dates and the “Pre-order protected by” branding must be displayed near the “Pre-order” call to action. Purple Dot provides a Web Component that can be used with any JS framework like this:

1. Place a `<purple-dot-learn-more />` HTML element anywhere in the DOM. This component is framework-agnostic and is compatible with all popular frameworks like React and Vue.

### Shopper self-service portal component

Purple Dot provides a portal where shoppers can manage their pre-orders. The portal can be embedded onto any page in your storefront:

1. Create a new page that can host the portal, e.g. `/pages/manage-pre-orders`
2. Initialize the Purple Dot SDK on this page by running

   ```typescript
   import * as PurpleDot from '@purple-dot/browser';

   PurpleDot.init({
     apiKey: '<Purple Dot API key>'
   });
   ```
3. Place a `<purple-dot-self-service />` HTML element where you would like the self service iframe to appear. This component is framework-agnostic and is compatible with all popular frameworks like React and Vue.

### Working with the cart

Purple Dot is compatible with several cart implementations:

* Standard AJAX cart used by Liquid storefronts
* Storefront API used by Hydrogen and headless storefronts
* Custom cart implementations (coming soon)

In order for Purple Dot to be able to interact with your cart, an adapter must be provided. The library includes pre-built adapters for the AJAX and Storefront API carts. They should be passed in as configuration when initialising the library.

```jsx
import * as PurpleDot from '@purple-dot/browser';
import { ShopifyAJAXCart } from '@purple-dot/browser/shopify-ajax-cart';

PurpleDot.init({
  apiKey: '<Purple Dot API key>',
  cartAdapter: new ShopifyAJAXCart(),
});
```

```jsx
import * as PurpleDot from '@purple-dot/browser';
import { ShopifyStorefrontCart } from '@purple-dot/browser/shopify-storefront-cart';

PurpleDot.init({
  apiKey: '<Purple Dot API key>',
  cartAdapter: new ShopifyStorefrontCart(
    'your-store.myshopify.com',
    '<Storefront API public access token>'
  ),
});
```

### Cart interceptors for AJAX API (`@purple-dot/browser/shopify-ajax-interceptors`)

Whenever a pre-order item is added to cart, from anywhere on the storefront, pre-order metadata must be added to it as line item properties. This can be achieved by making sure that anywhere that adds to cart accounts for pre-orders, or by intercepting and modifying all requests to the cart API. The interceptors package will use the provided cart adapter. It is used like:

```jsx
import * as interceptors from '@purple-dot/browser/shopify-ajax-interceptors';

interceptors.start();
```

The library will intercept any requests to the cart API, use the pre-order state API to determine if an item is a pre-order, and add the required metadata. It adds two line item properties, `__releaseId` (hidden), which indicates the Purple Dot waitlist, and `Purple Dot Pre-order` which contains the ship dates, and should be shown in the side cart.

### Cart state (`@purple-dot/browser/cart`)

In order to redirect the shopper to the Purple Dot pre-order checkout, we need to know if the cart contains a pre-order. That can be done like:

```jsx
import { cartHasPreorderItem } from '@purple-dot/browser/cart';

// When using the AJAX cart API, cart is fetched automatically
if (await cartHasPreorderItem()) {
  // ...
}

// When using the Storefront cart API, a cart object has to be provided
if (await cartHasPreorderItem(cart)) {
  // ...
}
```

The library fetches the latest cart state from the cart using the configured adapter and check if it contains a pre-order item by inspect the line item properties and checking for the presence of `__releaseId`.

### Pre-order checkout (`@purple-dot/browser/checkout`)

If the cart contains a pre-order item, the shopper has to checkout using the Purple Dot pre-order checkout instead of the standard Shopify checkout. The checkout loads as a full-page iframe and can be opened from any page on the site.&#x20;

If the storefront has a `/cart` page, the checkout should be opened on page load. The checkout will use the configured cart adapter and is opened and closed like this:

```jsx
import * as checkout from '@purple-dot/browser/checkout';

// When using the AJAX cart API, cart id is determined automatically
await checkout.open();

// When using the Storefront cart API, cart id must be passed in
await checkout.open({ cartId: 'gid://Cart/...' });
```

```javascript
// Close the checkout
await checkout.purpleDotCheckout((c) => c.close());
```


# Shopify Headless - Express Checkout

## Express checkout overview

The Express checkout flow uses Purple Dot’s own cart system, separate from your store’s Shopify cart. Each pre-order is handled in its own lightweight cart and checked out individually through the Purple Dot Express checkout modal. Shoppers will not see these items appear in the normal Shopify cart.

There are 3 key requirements an integration needs to implement for an Express checkout:

* **Displaying pre-order items.** Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The integration needs to show that those items are on pre-order, with the estimated ship dates, the "Learn more” informational content and a “Pre-order” call to action.
* **Using the Express pre-order checkout.** When pre-ordering an item, instead of adding the item to the cart, the integration needs to launch our Express checkout modal and provide the variant ID, release ID, currency, and quantity.
* **Shopper portal.** The shopper self-service portal lets shoppers manage their pre-orders. The integration needs to be embedded on a page in the storefront that the shoppers will be directed to in their confirmation email.

### Displaying pre-order items

Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The[ Pre-order availability API](#pre-order-availability-api) can be queried for the pre-order status of any product or variant on the store.

When a variant has an open waitlist, it will be set to “continue selling” in Shopify, and how it should be displayed is determined by the [Pre-order availability API](#pre-order-availability-api).

#### Product pages

Anywhere a product can be added to cart - on product pages, or collection pages and elsewhere with add to cart controls - the integration should use the variant's pre-order state provided by the [Pre-order availability API](#pre-order-availability-api) to determine how a variant should be treated. There are 4 possible states:

* `NO_WAITLISTS` state means the variant has no open waitlists and no changes need to be made.
* `AVAILABLE_IN_STOCK` state means the variant has an open waitlist but also has stock available in Shopify, and should be treated like a regular in-stock product.
* `ON_PREORDER` state means the variant has an open waitlist and no stock in Shopify and should be treated as a pre-order. The following should be shown:
  * Change the add to cart button label to “Pre-order”, if the button has a label.
  * Show the estimated ship dates. This is the `display_dispatch_date` as returned by the 2 [Pre-order availability API](#pre-order-availability-api) endpoints.
  * Show the [Learn more](#learn-more-component) component near the button.
* `SOLD_OUT` state means the variant has an open waitlist but no stock in Purple Dot or Shopify. The add to cart button must be disabled and the label should be changed to “Sold out”.

Whenever a new variant is selected, for example using a size or colour picker, the [Pre-order availability API](#pre-order-availability-api) state should be used to determine how to display the newly selected variant. For products with multiple variants, it is possible for some variants to be on pre-order while others are in-stock or sold out.

#### Collection pages

On collection pages and in any panels that list products, the integration may show a “Pre-order” label for products that are fully on pre-order, using the state provided by the product pre-order state endpoint. The possible states are the same as for a single variant, but take into account all of the product's variants, and are therefore suitable for cases where no variant is selected.

### Using the Express pre-order checkout

When a shopper clicks the Pre-order button, instead of adding the pre-order item to the cart, launch the Purple Dot Express checkout for just that specific item.

Purple Dot provides a pre-built component (see below) for that will launch the checkout on the page as an overlay iframe.

### Shopper portal

The shopper portal is an iframe that embeds a portal that lets shoppers manage their pre-orders. The integration must embed the shopper portal component on a dedicated page, so that shoppers can be linked to it from their confirmation emails.

## Components

Purple Dot provides a package that includes the components needed for the integration. It can be installed from `npm`, and must be included and initialised whenever the storefront is loaded.

```bash
npm install -S @purple-dot/browser
```

```jsx
import * as PurpleDot from '@purple-dot/browser';

PurpleDot.init({
  apiKey: 'xxx',
});
```

> 💡 Your API key can be found in the Merchant Portal under Settings > Integration.

When initialised, it will inject a `<script>` tag that loads additional code required to make Purple Dot work.

The package contains several modules structured like this:

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FNaWBrYziOxKecIsyif7e%2FScreenshot%202023-08-02%20at%2019.23.48.png?alt=media&amp;token=ffcb9b23-1a14-4964-9594-8875d266ed3a" alt=""><figcaption><p><code>@purple-dot/browser</code> structure</p></figcaption></figure>

### Pre-order availability API

The pre-order availability API should be used for determining if a product or a variant should be displayed as a pre-order and the estimated ship dates if so.

Purple Dot provides a client library that can be used like:

```jsx
import * as api from '@purple-dot/browser/api';

const variantResponse = await api.fetchVariantsPreorderState(variant.id);

const productResponse = await api.fetchProductsPreorderState(product.handle);
```

* `variantPreorderState` provides data on the pre-order state of any variant. It should be used when interacting with a specific variant, such as on a product page. It returns:
  * `state`, one of:
    * `NO_WAITLISTS` - the variant has no open waitlists and no pre-order related functionality should trigger
    * `AVAILABLE_IN_STOCK` - the variant is available in stock and should not be sold as a pre-order (even though there is an open waitlist)
    * `ON_PREORDER` - the variant is available as a pre-order only
    * `SOLD_OUT` - the variant is completely sold out, in stock and on pre-order
  * `waitlist`
    * `id` - the waitlist ID
    * `display_dispatch_date` - the estimated ship date to display for the variant if on pre-order
* `productPreorderState` provides data on the pre-order state of a whole product. It can be used in contexts where no variant is selected, such as on a collection page. It returns:
  * `state`, one of:
    * `NO_WAITLISTS` - the product has no open waitlists and no pre-order related functionality should trigger
    * `AVAILABLE_IN_STOCK` - the product has some variants available in stock, and should be displayed as a regular in-stock product
    * `ON_PREORDER` - the product has all variants available on pre-order, and should be displayed as a pre-order product
    * `SOLD_OUT` - the product is completely sold out
  * `waitlist`
    * `id` - the waitlist ID
    * `display_dispatch_date` - the estimated ship date to display for the product if on pre-order

### Learn more component

When a variant is on pre-order, the estimated ship dates and the “Pre-order protected by” branding must be displayed near the “Pre-order” call to action. Purple Dot provides a Web Component that can be used with any JS framework like this:

1. Place a `<purple-dot-learn-more />` HTML element anywhere in the DOM. This component is framework-agnostic and is compatible with all popular frameworks like React and Vue.

### Shopper self-service portal component

Purple Dot provides a portal where shoppers can manage their pre-orders. The portal can be embedded onto any page in your storefront:

1. Create a new page that can host the portal, e.g. `/pages/manage-pre-orders`
2. Initialize the Purple Dot SDK on this page by running

   ```typescript
   import * as PurpleDot from '@purple-dot/browser';

   PurpleDot.init({
     apiKey: '<Purple Dot API key>'
   });
   ```
3. Place a `<purple-dot-self-service />` HTML element where you would like the self service iframe to appear. This component is framework-agnostic and is compatible with all popular frameworks like React and Vue.

### Working with the cart

Purple Dot is compatible with several cart implementations:

* Standard AJAX cart used by Liquid storefronts
* Storefront API used by Hydrogen and headless storefronts
* Custom cart implementations (coming soon)

In order for Purple Dot to be able to interact with your cart, an adapter must be provided. The library includes pre-built adapters for the AJAX and Storefront API carts. They should be passed in as configuration when initialising the library.

```jsx
import * as PurpleDot from '@purple-dot/browser';
import { ShopifyAJAXCart } from '@purple-dot/browser/shopify-ajax-cart';

PurpleDot.init({
  apiKey: '<Purple Dot API key>',
  cartAdapter: new ShopifyAJAXCart(),
});
```

```jsx
import * as PurpleDot from '@purple-dot/browser';
import { ShopifyStorefrontCart } from '@purple-dot/browser/shopify-storefront-cart';

PurpleDot.init({
  apiKey: '<Purple Dot API key>',
  cartAdapter: new ShopifyStorefrontCart(
    'your-store.myshopify.com',
    '<Storefront API public access token>'
  ),
});
```

### Cart interceptors for AJAX API (`@purple-dot/browser/shopify-ajax-interceptors`)

Whenever a pre-order item is added to cart, from anywhere on the storefront, pre-order metadata must be added to it as line item properties. This can be achieved by making sure that anywhere that adds to cart accounts for pre-orders, or by intercepting and modifying all requests to the cart API. The interceptors package will use the provided cart adapter. It is used like:

```jsx
import * as interceptors from '@purple-dot/browser/shopify-ajax-interceptors';

interceptors.start();
```

The library will intercept any requests to the cart API, use the pre-order state API to determine if an item is a pre-order, and add the required metadata. It adds two line item properties, `__releaseId` (hidden), which indicates the Purple Dot waitlist, and `Purple Dot Pre-order` which contains the ship dates, and should be shown in the side cart.

### Cart state (`@purple-dot/browser/cart`)

In order to redirect the shopper to the Purple Dot pre-order checkout, we need to know if the cart contains a pre-order. That can be done like:

```jsx
import { cartHasPreorderItem } from '@purple-dot/browser/cart';

// When using the AJAX cart API, cart is fetched automatically
if (await cartHasPreorderItem()) {
  // ...
}

// When using the Storefront cart API, a cart object has to be provided
if (await cartHasPreorderItem(cart)) {
  // ...
}
```

The library fetches the latest cart state from the cart using the configured adapter and check if it contains a pre-order item by inspect the line item properties and checking for the presence of `__releaseId`.

### Pre-order checkout (`@purple-dot/browser/checkout`)

Instead of adding a pre-order item to the cart, an express checkout allows the shopper to pre-order the item right away. The express checkout should be launched within a click handler for the Add To Cart/Pre-order button:

```javascript
import * as checkout from '@purple-dot/browser/checkout';

// Get the pre-order button element
const preorderButton = document.getElementById("preorderButton");

// Add an event listener for the button's "click" event
preorderButton.addEventListener("click", function() {
  await checkout.openExpressCheckout({
    variantId: '41234567890...',   // Shopify variant ID as a string
    releaseId: 'f47ac10b-58cc...', // Purple Dot release ID from variantPreorderState.waitlist
    currency: 'USD',               
    quantity: 1,                   // 1, or the value from the quantity selector if there is one
  });
});
```


# Integrate into Shopify Hydrogen Storefronts

## Hydrogen integration overview

Purple Dot integrates with your existing storefront and enables you to create pre-order experiences. When integrating with a hydrogen storefront Purple Dot, provides a set of components that can be used to build the integration.

Purple Dot supports [**Combined**](/docs/shopify-stores/integrate-purple-dot-with-your-storefront/integrate-into-shopify-hydrogen-storefronts/shopify-hydrogen-combined-checkout) checkout flows for hydrogen stores. This checkout method allows the shopper to add a pre-order item to their cart, but also continue shopping for other in-stock and pre-order items. When they are ready to checkout, they can be presented with a checkout that allows them to combine both pre-order and in-stock items at once, and choose to either ship them together or separately. This flow uses your store’s normal Shopify cart.

{% hint style="info" %}
If you are unsure which checkout flow your store is configured for, please reach out to Purple Dot Support to confirm, or to switch from one checkout method to another.
{% endhint %}


# Shopify Hydrogen - Combined Checkout

*This guide will walk you through Purple Dot's Platform integration into any Shopify Hydrogen Storefront.*

## Combined checkout overview

The Combined Checkout flow uses your store’s normal Shopify cart, unlike the Express flow, which uses Purple Dot’s own cart. This means that pre-order and in-stock items coexist within the same Shopify cart, and Purple Dot’s integration layers on top of your existing cart implementation to manage pre-order metadata and checkout routing.

There are 5 key requirements an integration needs to implement for a Combined Checkout:

* **Displaying pre-order items.** Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The integration needs to show that those items are on pre-order, with the estimated ship dates, the "Learn more” informational content, and a “Pre-order” call to action.
* **Adding pre-order items to cart.** When adding an item to the cart, the integration needs to determine if it is a pre-order and attach the waitlist ID and ship dates if it is.
* **Showing pre-order items in cart.** When a pre-order item is in the cart, the estimated ship dates need to be displayed.
* **Using the Combined pre-order checkout.** The Purple Dot pre-order checkout lets shoppers checkout with pre-order items. When a pre-order item is in the cart, the integration needs to direct the shopper to the Purple Dot pre-order checkout instead of the Shopify checkout.
* **Shopper portal.** The shopper self-service portal lets shoppers manage their pre-orders. The integration needs to be embedded on a page in the storefront that the shoppers will be directed to in their confirmation email.

## Install the Purple Dot browser package

```bash
npm install @purple-dot/browser
```

## Setup vite config

If you're using vite in your hydrogen storefront, update the `vite.config.ts`  file with the following:

```javascript
export default defineConfig({
  plugins: [
    // ...
  ],
  build: {
    // ...
  },
  ssr: {
    optimizeDeps: {
      include: [
        '@purple-dot/browser/*'],
      ],
    },
  },
});
```

## Add config variables

In your `.env` file and in `remix.env.d.ts`, add `PURPLE_DOT_API_KEY` and set it to the public API key you can find in the [integration page](https://www.purpledotprice.com/merchant-portal/integration) of your Purple Dot merchant portal. You must also have `PUBLIC_STOREFRONT_API_TOKEN` and `PUBLIC_STORE_DOMAIN` set.

## Initialise the package

Before you can use the package, it needs to be initialised with your store's `apiKey` and the Storefront cart adapter. This needs to be initialised on each loader that requires the use of the package so that you can use the package in your backend handlers as well as React components:

```tsx
// Server-side
import * as PurpleDot from '@purple-dot/browser';
import { ShopifyStorefrontCart } from '@purple-dot/browser/shopify-storefront-cart';

export async function loader({context}: LoaderArgs) {
  const publicStoreDomain = context.env.PUBLIC_STORE_DOMAIN;
  const publicStorefrontApiToken = context.env.PUBLIC_STOREFRONT_API_TOKEN;
  const purpleDotApiKey = context.env.PURPLE_DOT_API_KEY;

  PurpleDot.init({
    apiKey: purpleDotApiKey,
    cartAdapter: new ShopifyStorefrontCart(
      publicStoreDomain,
      publicStorefrontApiToken,
    ),
  });

  // Use Purple Dot SDK...

  // Return data to page
  return defer(
    {
      // ...
      publicStoreDomain,
      publicStorefrontApiToken,
      purpleDotApiKey,
    },
    {headers},
  );
}

// Client-side

import * as PurpleDot from '@purple-dot/browser';
import { ShopifyStorefrontCart } from '@purple-dot/browser/shopify-storefront-cart';

export default function App() {
  const data = useLoaderData<typeof loader>();

  useEffect(() => {
    PurpleDot.init({
      apiKey: data.purpleDotApiKey,
      cartAdapter: new ShopifyStorefrontCart(
        data.publicStoreDomain,
        data.publicStorefrontApiToken,
      ),
    });
  }, []);

  return (
    <html lang="en">...</html>
  );
}
```

## Set up product pages

On every product form, two elements are expected if a variant/product is on preorder:

1. The waitlist shipping dates so that shoppers know when to expect their order to start shipping
2. A Purple Dot learn more element so that shoppers can understand their preorder process with Purple Dot

A non-preorder product:

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FsRYNfMKWwDgWuDODZVZg%2FScreenshot%25202023-08-02%2520at%252010.48.19%2520PM.png?alt=media&amp;token=4bcfae18-c9e1-400a-a50e-e8527260605a" alt=""><figcaption></figcaption></figure>

A pre-order product:

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FYY49fXqQxPaPnr0K2zOy%2FScreenshot%25202023-08-02%2520at%252010.47.50%2520PM.png?alt=media&amp;token=f2820099-9ca0-4ff9-a630-fb691b2f5807" alt=""><figcaption></figcaption></figure>

In the following example, we are going to fetch the preorder data in the loader:

```tsx
// routes/products.$handle.tsx
import * as api from '@purple-dot/browser/api';

function idFromGuid(guid: string): number {
    return parseInt(guid.split('/')[4], 10);
}

export async function loader({params, request, context}: LoaderArgs) {
  const {handle} = params;
  const {storefront} = context;

  const product = await getProduct(handle, params);

  const productRes = await api.fetchProductsPreorderState(handle);
  const variantRes = await api.fetchVariantsPreorderState(idFromGuid(product.selectedVariant.id));

  return defer({
    product: {
      ...product,
      isPreorder: productRes?.state === 'ON_PREORDER',
      selectedVariant: {
        ...product.selectedVariant,
        isPreorder: variantRes?.state === 'ON_PREORDER',
        releaseId: variantRes?.waitlist?.id,
        estimatedShipDates: variantRes?.waitlist?.display_dispatch_date,
        // Only required if using Shopify checkout
        sellingPlanId: variantRes?.waitlist?.selling_plan_id,
        compatibleCheckouts: variantRes?.waitlist?.compatible_checkouts,
      },
    },
    variants,
  });
}
```

Then display the preorder information on the product form if the variant is on pre-order:

```tsx
// routes/products.$handle.tsx
export default function Product() {
  const {product, variants} = useLoaderData<typeof loader>();
  const {selectedVariant} = product;

  return (
    <div className="product">
      <ProductImage image={selectedVariant?.image} />
      <ProductMain
        selectedVariant={selectedVariant}
        product={product}
        variants={variants}
      />
    </div>
  );
}

function ProductMain({
  selectedVariant,
  product,
  variants,
}: {
  product: ProductFragment;
  selectedVariant: ProductFragment['selectedVariant'];
  variants: Promise<ProductVariantsQuery>;
}) {
  const {title, descriptionHtml} = product;
  return (
    <div className="product-main">
      <h1>{title}</h1>
      <ProductPrice selectedVariant={selectedVariant} />
      <br />
      <Suspense
        fallback={
          <ProductForm
            product={product}
            selectedVariant={selectedVariant}
            variants={[]}
          />
        }
      >
        <Await
          errorElement="There was a problem loading product variants"
          resolve={variants}
        >
          {(data) => (
            <ProductForm
              product={product}
              selectedVariant={selectedVariant}
              variants={data.product?.variants.nodes || []}
            />
          )}
        </Await>
      </Suspense>
      <br />
      <br />
      <p>
        <strong>Description</strong>
      </p>
      <br />
      <div dangerouslySetInnerHTML={{__html: descriptionHtml}} />
      <br />
    </div>
  );
}

function ProductForm({
  product,
  selectedVariant,
  variants,
}: {
  product: ProductFragment;
  selectedVariant: ProductFragment['selectedVariant'] & {
    isPreorder: boolean;
    releaseId: string | null;
    estimatedShipDates: string | null;
    sellingPlanId?: string | null;
    compatibleCheckouts?: string[];
  };
  variants: Array<ProductVariantFragment>;
}) {
  const buttonLabel = selectedVariant?.availableForSale
    ? selectedVariant?.isPreorder ? 'Pre-order' : 'Add to cart'
    : 'Sold out';
  return (
    <div className="product-form">
      <VariantSelector
        handle={product.handle}
        options={product.options}
        variants={variants}
      >
        {({option}) => <ProductOptions key={option.name} option={option} />}
      </VariantSelector>
      <br />
      <AddToCartButton
        disabled={!selectedVariant || !selectedVariant.availableForSale}
        onClick={() => {
          window.location.href = window.location.href + '#cart-aside';
        }}
        lines={[
          {
            merchandiseId: selectedVariant.id,
            quantity: 1,
          }
        ]}
      >
        {buttonLabel}
      </AddToCartButton>
      {
         selectedVariant?.isPreorder &&
           <div>
             {selectedVariant?.estimatedShipDates}
           </div>
      }
      {selectedVariant?.isPreorder && <purple-dot-learn-more />}
    </div>
  );
}
```

## Set the right line item properties when adding to cart

The Purple Dot package expects the `__releaseId` property to exist on the line item to detect preorders in the shopper’s cart. You can easily add this by modifying your add to cart calls. Here’s how you can do it using the standard `AddToCartButton` element.

```tsx
// routes/products.$handle.tsx
import { purpleDotAttributes } from '@purple-dot/browser/cart';

function ProductForm({
  product,
  selectedVariant,
  variants,
}: {
  product: ProductFragment;
  selectedVariant: ProductFragment['selectedVariant'] & { isPreorder: boolean, releaseId: string, estimatedShipDates: string };
  variants: Array<ProductVariantFragment>;
}) {
  const buttonLabel = selectedVariant?.availableForSale
    ? selectedVariant?.isPreorder ? 'Pre-order' : 'Add to cart'
    : 'Sold out';

  return (
    <div className="product-form">
      <VariantSelector
        handle={product.handle}
        options={product.options}
        variants={variants}
      >
        {({option}) => <ProductOptions key={option.name} option={option} />}
      </VariantSelector>
      <br />
      <AddToCartButton
        disabled={!selectedVariant || !selectedVariant.availableForSale}
        onClick={() => {
          window.location.href = window.location.href + '#cart-aside';
        }}
        lines={
          selectedVariant
            ? [
                {
                  merchandiseId: selectedVariant.id,
                  quantity: 1,
                  sellingPlanId: selectedVariant.sellingPlanId,
                  attributes: purpleDotAttributes(selectedVariant),
                },
              ]
            : []
        }
      >
        {buttonLabel}
      </AddToCartButton>
      {
        selectedVariant?.isPreorder &&
          <div>
            {selectedVariant?.estimatedShipDates}
          </div>
      }
      {selectedVariant?.isPreorder && <purple-dot-learn-more />}
    </div>
  );
}
```

## Display preorder shipping date in your side cart

You can use the `Purple Dot Preorder` property that you added in your line item to differentiate preorder items in the side cart. For example, with a `CartLineItem.tsx` file that contains the component to display each line item in the shoppers, here’s how you can do it:

```tsx
// CartLineItem.tsx
export function CartLineItem(lineItem) {
  return (
    <LineItemContainer>
      <ProductImage variant={lineItem.variant} />
        <div>
          {lineItem.productName}
        </div>
        <ProductPrice variant={lineItem.variant} />
        {lineItem.attributes.find(({ key }) => key === 'Purple Dot Preorder')?.value}
      </LineItemContainer>
  );
}
```

## Open the Purple Dot checkout

Once the shoppers have added their preorder items to the cart, it’s time to let them checkout through the Purple Dot checkout. You can do this on the cart page as shown below:

```tsx
// app/pages/cart.tsx
import * as checkout from '@purple-dot/browser/checkout';
import { cartHasPreorderItem } from '@purple-dot/browser/cart';

export default function Cart() {
  const [root] = useMatches();
  const cart = root.data?.cart as Promise<CartApiQueryFragment | null>;

  return (
    <div className="cart">
      <h1>Cart</h1>
      <Suspense fallback={<p>Loading cart ...</p>}>
        <Await errorElement={<div>An error occurred</div>} resolve={cart}>
          {(cart) => {

            // Open Purple Dot checkout if the cart contains a pre-order
            useEffect(() => {
              if (cart) {
                cartHasPreorderItem(cart.lines.nodes).then((hasPreorderItem) => {
                  if (hasPreorderItem) {
                    checkout.open({
                      cartId: cart.id,
                      // Pass in a random, stable sessionId if using Shopify checkout
                      sessionId,
                    });
                  }
                });
              }
            }, [cart?.id]);

            return <CartMain layout="page" cart={cart} />;
          }}
        </Await>
      </Suspense>
    </div>
  );
}
```

This opens up an iframe that allows the shopper to checkout with Purple Dot.

## Embed the Purple Dot self-service for shoppers to manage their preorders

Pick any page where you’d like to display the Purple Dot self-service and embed the Purple Dot self-service as shown below:

```tsx
export function SelfServicePage() {
  return (
    <PageContainer>
      <purple-dot-self-service />
    </PageContainer>
  );
}
```

Add the URL of this page to the Cancel link within Settings > Email in the merchant portal.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FMpTeWYuuLEH1ZTyIJHfb%2FCleanShot%202024-09-27%20at%2013.50.17.png?alt=media&amp;token=a773d46e-cc3e-48b8-9160-8da8f7ba38e4" alt=""><figcaption></figcaption></figure>


# Integrate into React Native apps

## React Native integration overview

Purple Dot integrates with your existing React Native mobile apps and enables you to create pre-order experiences. When integrating with a React Native app, Purple Dot provides a set of components that can be used to build the integration.

Purple Dot supports the [**Combined Checkout**](/docs/shopify-stores/integrate-purple-dot-with-your-storefront/integrate-into-shopify-hydrogen-storefronts/shopify-hydrogen-combined-checkout) flow for React Native apps. This checkout method allows the shopper to add a pre-order item to their cart, but also continue shopping for other in-stock and pre-order items. When they are ready to checkout, they can be presented with a checkout that allows them to combine both pre-order and in-stock items at once, and choose to either ship them together or separately. This flow uses your app's normal Shopify Storefront cart.

{% hint style="info" %}
If you are unsure which checkout flow your store is configured for, please reach out to Purple Dot Support to confirm, or to switch from one checkout method to another.
{% endhint %}


# React Native - Combined Checkout

## Combined Checkout overview

The Combined Checkout flow uses your store’s normal Shopify cart, unlike the Express flow, which uses Purple Dot’s own cart. This means that pre-order and in-stock items coexist within the same Shopify cart, and Purple Dot’s integration layers on top of your existing cart implementation to manage pre-order metadata and checkout routing.

There are 5 key requirements an integration needs to implement for a Combined Checkout:

* **Displaying pre-order items.** Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The integration needs to show that those items are on pre-order, with the estimated ship dates, the "Learn more” informational content and a “Pre-order” call to action.
* **Adding pre-order items to cart.** When adding an item to cart, the integration needs to determine if it is a pre-order, and attach the waitlist ID and ship dates if it is.
* **Showing pre-order items in cart.** When a pre-order item is in the cart, the estimated ship dates need to be displayed.
* **Using the Combined pre-order checkout.** The Purple Dot pre-order checkout lets shoppers checkout with pre-order items. When a pre-order item is in the cart, the integration needs to direct the shopper to the Purple Dot pre-order checkout instead of the Shopify checkout.
* **Shopper portal.** The shopper self-service portal lets shoppers manage their pre-orders. The integration needs to be embedded on a page in the storefront that the shoppers will be directed to in their confirmation email.

### Displaying pre-order items

Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The [Pre-order availability API](#pre-order-availability-api) can be queried for the pre-order status of any product or variant on the store.

When a variant has an open waitlist, it will be set to “continue selling” in Shopify, and how it should be displayed is determined by the [Pre-order availability API](#pre-order-availability-api).

#### Product pages

Anywhere a product can be added to cart—on product pages, or collection pages and elsewhere with add to cart controls—the integration should use the variant's pre-order state provided by the [Pre-order availability API](#pre-order-availability-api) to determine how a variant should be treated. There are 4 possible states:

* `NO_OPEN_WAITLISTS` state means the variant has no open waitlists and no changes need to be made.
* `AVAILABLE_IN_STOCK` state means the variant has an open waitlist but also has stock available in Shopify, and should be treated like a regular in-stock product.
* `ON_PREORDER` state means the variant has an open waitlist and no stock in Shopify and should be treated as a pre-order. The following should be shown:
  * Change the add to cart button label to “Pre-order”, if the button has a label.
  * Show the estimated ship dates. This is the `display_dispatch_date` as returned by the 2 [Pre-order availability API](#pre-order-availability-api) endpoints.
  * Show the [Learn more](#learn-more-component) component near the button.
* `SOLD_OUT` state means the variant has an open waitlist but no stock in Purple Dot or Shopify. The add to cart button must be disabled and the label should be changed to “Sold out”.

Whenever a new variant is selected, for example using a size or colour picker, the [Pre-order availability API](#pre-order-availability-api) state should be used to determine how to display the newly selected variant. For products with multiple variants, it is possible for some variants to be on pre-order while others are in-stock or sold out.

#### Collection pages

On collection pages and in any panels that list products, the integration may show a “Pre-order” label for products that are fully on pre-order, using the state provided by the product pre-order state endpoint. The possible states are the same as for a single variant, but take into account all of the product's variants, and are therefore suitable for cases where no variant is selected.

### Adding pre-order items to cart

Whenever a pre-order item is added to cart, two line item properties must be added to it:

* `__releaseId`, a hidden property whose value indicates which waitlist it's on. This is the `id` as returned by the two [Pre-order availability API](#pre-order-availability-api) endpoints.
* `Purple Dot Pre-order`, a property whose value has the estimated ship dates and that indicates that something is a pre-order. This is the `display_dispatch_date` as returned by the two [Pre-order availability API](#pre-order-availability-api) endpoints.

Whenever an item is added to cart from anywhere on the site, it's pre-order status needs to be checked, and properties added if it is in `ON_PREORDER` or `SOLD_OUT` state (nothing needs to be done if it is `NO_OPEN_WAITLISTS` or `AVAILABLE_IN_STOCK` state).

If using the Storefront API, the integration must take care to always attach these properties when a pre-order item is added to cart.

### Showing pre-order items in cart

When displaying items in the side cart or on a cart page, the `Purple Dot Pre-order` line item property should always be displayed. It indicates that the item is a pre-order and its estimated ship dates.

Many Shopify mobile apps already display the cart item properties, so this should happen automatically. If not, you need to make sure the property is shown in the side cart and on the cart page.

### Using the Combined pre-order checkout

In order to hold pre-orders outside your downstream systems and for FTC compliance, the mirrored Purple Dot pre-order checkout is used when the shopper is checking out with pre-order items in their card. When a pre-order item is in the cart, the integration needs to open up a new WebView that presents the shopper with                                                                                                                                                                       the Purple Dot checkout instead of the Shopify checkout. Purple Dot provides a pre-built component for checking the cart state (see below), which can be used to conditionally change any links to the checkout.

The pre-order checkout can be opened on any page as an overlay iframe, or it can be hosted on the cart page and opened conditionally on load.

### Shopper portal

The shopper portal is an iframe that embeds a portal that lets shoppers manage their pre-orders. The integration must embed the shopper portal component on a dedicated page, so that shoppers can be linked to it from their confirmation emails.

## Components

Purple Dot provides a package that includes the components needed for the integration. It can be installed from `npm`, and must be included and initialised whenever the storefront is loaded.

```bash
npm install -S @purple-dot/browser
```

```jsx
import * as PurpleDot from '@purple-dot/browser';

PurpleDot.init({
  apiKey: 'xxx',
});
```

> 💡 Your API key can be found in the Merchant Portal under Settings > Integration.

When initialised, it will inject a `<script>` tag that loads additional code required to make Purple Dot work.

The package contains several modules structured like this:

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FNaWBrYziOxKecIsyif7e%2FScreenshot%202023-08-02%20at%2019.23.48.png?alt=media&amp;token=ffcb9b23-1a14-4964-9594-8875d266ed3a" alt=""><figcaption><p><code>@purple-dot/browser</code> structure</p></figcaption></figure>

### Pre-order availability API

The pre-order availability API should be used for determining if a product or a variant should be displayed as a pre-order and the estimated ship dates if so.

Purple Dot provides a client library that can be used like:

```jsx
import * as api from '@purple-dot/browser/api';

const variantResponse = await api.fetchVariantsPreorderState(variant.id);

const productResponse = await api.fetchProductsPreorderState(product.handle);
```

* `variantPreorderState` provides data on the pre-order state of any variant. It should be used when interacting with a specific variant, such as on a product page. It returns:
  * `state`, one of:
    * `NO_OPEN_WAITLISTS` - the variant has no open waitlists and no pre-order related functionality should trigger
    * `AVAILABLE_IN_STOCK` - the variant is available in stock and should not be sold as a pre-order (even though there is an open waitlist)
    * `ON_PREORDER` - the variant is available as a pre-order only
    * `SOLD_OUT` - the variant is completely sold out, in stock and on pre-order
  * `waitlist`
    * `id` - the waitlist ID
    * `display_dispatch_date` - the estimated ship date to display for the variant if on pre-order
* `productPreorderState` provides data on the pre-order state of a whole product. It can be used in contexts where no variant is selected, such as on a collection page. It returns:
  * `state`, one of:
    * `NO_OPEN_WAITLISTS` - the product has no open waitlists and no pre-order related functionality should trigger
    * `AVAILABLE_IN_STOCK` - the product has some variants available in stock, and should be displayed as a regular in-stock product
    * `ON_PREORDER` - the product has all variants available on pre-order, and should be displayed as a pre-order product
    * `SOLD_OUT` - the product is completely sold out
  * `waitlist`
    * `id` - the waitlist ID
    * `display_dispatch_date` - the estimated ship date to display for the product if on pre-order

### Learn more component

When a variant is on pre-order, the estimated ship dates and the “Pre-order protected by” branding must be displayed near the “Pre-order” call to action. Purple Dot provides a Web Component that can be used with any JS framework like this:

1. Place a `<purple-dot-learn-more />` HTML element anywhere in the DOM. This component is framework-agnostic and is compatible with all popular frameworks like React and Vue.

### Shopper self-service portal component

Purple Dot provides a portal where shoppers can manage their pre-orders. The portal can be embedded onto any page in your storefront:

1. Create a new page that can host the portal, e.g. `/pages/manage-pre-orders`
2. Initialize the Purple Dot SDK on this page by running

   ```typescript
   import * as PurpleDot from '@purple-dot/browser';

   PurpleDot.init({
     apiKey: '<Purple Dot API key>'
   });
   ```
3. Place a `<purple-dot-self-service />` HTML element where you would like the self service iframe to appear. This component is framework-agnostic and is compatible with all popular frameworks like React and Vue.

### Working with the cart

For React Native apps, Purple Dot requires the use of the Storefront API, typically used by Hydrogen and headless storefronts as well as many mobile apps. In order for Purple Dot to be able to interact with your cart, use the Shopify Storefront Cart adapter provided by the SDK. This should be passed in as configuration when initialising the library.

```jsx
import * as PurpleDot from '@purple-dot/browser';
import { ShopifyStorefrontCart } from '@purple-dot/browser/shopify-storefront-cart';

PurpleDot.init({
  apiKey: '<Purple Dot API key>',
  cartAdapter: new ShopifyStorefrontCart(
    'your-store.myshopify.com',
    '<Storefront API public access token>'
  ),
});
```

### Adding pre-order items to the cart

Whenever a pre-order item is added to cart, from anywhere on the storefront, pre-order metadata must be added to it as line item properties. This can be achieved by making sure that anywhere that items can be added to the cart first checks for the pre-order state of the variant using our Preorder Availability APIs, and adds the following line item attributes via GraphQL:

* `__releaseId`: the ID of the Purple Dot waitlist
* `Purple Dot Pre-order`: the estimated ship date to display for the product if on pre-order

Here's how an `addPreorderItemToCart` function may be implemented in Javascript:

<pre class="language-jsx"><code class="lang-jsx">/**
 * Adds a line item to the Shopify cart with preorder properties.
 * 
 * @param {string} cartId - The Shopify Cart GID.
 * @param {string} variantId - The Product Variant GID.
 * @param {string} waitlistId - The Purple Dot waitlist ID.
 * @param {string} dispatchDate - The estimated ship date for the Purple Dot Pre-order property.
 * @returns {Promise&#x3C;Object>} The response data from the Storefront API.
 */
async function addPreorderItemToCart(cartId, variantId, releaseId, dispatchDate) {
  const SHOP_DOMAIN = 'your-store.myshopify.com';
  const ACCESS_TOKEN = 'your_storefront_access_token';
  const API_VERSION = '2026-04';

  const mutation = `
    mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
      cartLinesAdd(cartId: $cartId, lines: $lines) {
        cart {
          id
          lines(first: 10) {
            nodes {
              id
              attributes {
                key
                value
              }
            }
          }
        }
        userErrors {
          field
          message
        }
      }
    }
  `;

  const variables = {
    cartId: cartId,
    lines: [
      {
        merchandiseId: variantId,
        quantity: 1,
<strong>        attributes: [
</strong><strong>          { key: "__releaseId", value: waitlistId },
</strong><strong>          { key: "Purple Dot Pre-order", value: dispatchDate }
</strong>        ]
      }
    ]
  };

  const response = await fetch(`https://${SHOP_DOMAIN}/api/${API_VERSION}/graphql.json`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Shopify-Storefront-Access-Token': ACCESS_TOKEN,
    },
    body: JSON.stringify({ query: mutation, variables }),
  });

  return await response.json();
}

</code></pre>

Example call:

```javascript
import * as api from '@purple-dot/browser/api';

async function handleAddToCart(cart, variant) {
    const variantResponse = await api.fetchVariantsPreorderState(variant.id);
    
    if (variantResponse.state === 'ON_PREORDER') {
        const waitlistId = variantResponse.waitlist.id;
        const dispatchDate = variantResponse.waitlist.display_dispatch_date;
        
        addPreorderItemToCart(cart.id, variant.id, waitlistId, dispatchDate);
    } else {
        // Add item to cart as you normally would
        // ...
    }
}
```

### Cart state (`@purple-dot/browser/cart`)

In order to redirect the shopper to the Purple Dot pre-order checkout, we need to know if the cart contains a pre-order. That can be done like:

```jsx
import { cartHasPreorderItem } from '@purple-dot/browser/cart';

if (await cartHasPreorderItem(cart)) {
  // ...
}
```

The library fetches the latest cart state from the cart using the configured adapter and check if it contains a pre-order item by inspect the line item properties and checking for the presence of `__releaseId`.

### Pre-order checkout

If the cart contains a pre-order item, the shopper has to checkout using the Purple Dot pre-order checkout instead of the standard Shopify checkout. The Purple Dot checkout can be launched in a WebView by going to the following URL:

`https://www.purpledotprice.com/embedded/placements/checkout/combined?apiKey=API_KEY&cartId=CART_ID&salesChannel=APP_NAME`&#x20;

Example:

```jsx
import React, { useMemo } from 'react';
import { WebView } from 'react-native-webview';

function buildCombinedCheckoutUrl(params: {
  apiKey: string;
  cartId: string;
  currency?: string;
  locale?: string;
  salesChannel?: string;
}) {
  const q = new URLSearchParams({ apiKey: params.apiKey, cartId: params.cartId });
  if (params.currency) q.set('currency', params.currency);
  if (params.locale) q.set('locale', params.locale);
  if (params.salesChannel) q.set('salesChannel', params.salesChannel);
  return `https://www.purpledotprice.com/embedded/placements/checkout/combined?${q.toString()}`;
}

export function PurpleDotCombinedCheckoutWebView(props: {
  apiKey: string;
  cartId: string;
  currency?: string;
  locale?: string;
  onOpened?: () => void;
  onClosed?: () => void;
}) {
  const apiKey = 'your-purple-dot-api-key';
  const salesChannel = 'your-app-name';
  
  const uri = useMemo(
    () => buildCombinedCheckoutUrl({ 
      apiKey, 
      cartId, 
      currency,
      locale,
    }),
    [apiKey, props.cartId, props.currency, props.locale]
  );

  return (
    <WebView
      source={{ uri }}
      onMessage={(event) => {
        const msg = event.nativeEvent.data;
        if (msg === 'pd:checkout_opened') {
          props.onOpened?.();
        }
        if (msg === 'pd:checkout_closed') {
          props.onClosed?.();
        }
      }}
    />
  );
}
```

The WebView will fire events than can be handled by providing callback functions to add custom logic for routing, analytics, etc. on checkout being opened or closed.


# Test the Integration

### [Sandbox Stores](#sandbox-stores) <a href="#sandbox-stores" id="sandbox-stores"></a>

Each store in Purple Dot is configured as either `Live` or `Sandbox`. A sandbox store doesn't process real payments and can be used for development or testing.

The sandbox attribute of a store is set when it's created and can't be changed later. Sandbox stores are indicated with a badge in your Merchant Portal and the checkout modal.

Our recommended integration approach is to create a sandbox store (e.g. `ACME Staging`) and connect it to your staging environment. When you're ready to go live, you can create a live store (e.g. `ACME UK`), connect it to your production store, and switch the sandbox API key for a production one.

### [Test Card Numbers](#test-card-numbers) <a href="#test-card-numbers" id="test-card-numbers"></a>

To test transactions in a sandbox store, you can use Stripe's [test card numbers](https://stripe.com/docs/testing#cards). A UK-based test card number is `4000 0082 6000 0000` and US-based test card number is `4242 4242 4242 4242`. You can use any expiry date, CVC, and ZIP/postcode with the test cards.

### [Accepting Orders](#accepting-orders) <a href="#accepting-orders" id="accepting-orders"></a>

When you export a pre-order from a sandbox store, an order is created in your connected store as normal.

To be able to export orders in a sandbox store, you must still connect a bank account. When connecting a bank account in a sandbox store, you can use Stripe's [test details](https://stripe.com/docs/connect/testing). No real money transfers are made in sandbox stores.

### [Test plans](#test-plans)

See <https://purple-dot.support.site/article/testing-purple-dot-checkout>.


# Pre-order Tracking

## **Shopify stores** <a href="#shopify-stores" id="shopify-stores"></a>

If/how you need to integrate Purple Dot with 3rd party tracking softwaredepends on whether Purple Dot is integrated into your Shopify store as separate checkout or as a payment provider inside Shopify's checkout. See more [here](https://docs.getpurpledot.com/docs#feature-comparison) to learn about these two options.

### **As payment provider inside Shopify checkout** <a href="#as-payment-provider-inside-shopify-checkout" id="as-payment-provider-inside-shopify-checkout"></a>

No extra setup is required. The same events/tracking that already works for your regular sales will work for pre-orders also. The rest of this section does not apply.

### **As separate checkout** <a href="#as-separate-checkout" id="as-separate-checkout"></a>

Once set up to do so, the Purple Dot checkout can send&#x20;

* ad attribution events,
* conversion events, and
* subscribe shoppers to email/sms marketing

to many different 3rd party systems. See pages below to learn more about the supported integrations and how to turn them on.

You can activate these integrations from the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/integration).


# Attentive integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled Attentive tracking on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), the Purple Dot checkout automatically sends certain events to TikTok via the [Events API](https://ads.tiktok.com/help/article/events-api).

### Steps to connect <a href="#steps-to-connect" id="steps-to-connect"></a>

1. Head to the **Settings** tab on the left-hand side of your [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations) dashboard.&#x20;
2. Click **Integrations**
3. Under **Attentive**, you can enter your Attentive Custom App API Key, Sign-up Source ID and Country.&#x20;
4. Hit **Save**.

#### **Attentive Custom App API Key** <a href="#attentive-custom-app-api-key" id="attentive-custom-app-api-key"></a>

To get your Attentive Custon App API Key, please create a custom app inside attentive (instructions here) <https://docs.attentive.com/pages/create-and-manage-custom-apps/>

Called "Purple Dot"

#### **Access Permissions** <a href="#access-permissions" id="access-permissions"></a>

```
Write Access for Custom Events
Write Access for Subscribers
```

#### **Sign-up Source ID** <a href="#sign-up-source-id" id="sign-up-source-id"></a>

To get the Sign-up Source ID you need to send an email like this to your Attentive account manager:

To: <whiteglove@attentivemobile.com> (or account manager if you have one)

*CC: \<business contact email>*

***Subject: Sign-Up Source ID for Creating Subscribers Using Custom App - Purple Dot***

*Hi Attentive Team,*

*We use Purple Dot (*[*www.getpurpledot.com*](http://www.getpurpledot.com)*) to transact our customers when they purchase a pre-order. We would also like to collect SMS subscribers in the Purple Dot checkout.*

*We have created the Purple Dot custom app and provided Purple Dot with the API Key. Please can you provide them with a Sign-up Source ID?*

*One of the Purple Dot team is in cc if you need more information.*

*Thanks,*


# Braze integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled the Braze integration from the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), when a shopper buys a pre‑order the Purple Dot checkout will send one `POST /users/track` request that:

1. Upserts marketing consent to the shopper’s profile  ( `attributes`)
2. Logs the `pre_order_placed` event (`events`)
3. Emits a purchase row per line‑item (`purchases`)

***

```
{
  "attributes": [
    {
      "email": "<shopper_email>",
      "has_email_marketing_consent": <true|false>,
      "has_sms_marketing_consent": <true|false>
    }
  ],
  "events": [
    {
      "email": "<shopper_email>",
      "name": "pre_order_placed",
      "time": "<ISO8601_timestamp>",
      "properties": {
        "order_id": "<pre_order_reference>",
        "source": "Purple Dot",
        "shipping": {
          "address": {
            "first_name": "<first_name>",
            "last_name": "<last_name>",
            "address1": "<address_line_1>",
            "address2": "<address_line_2>",
            "city": "<city>",
            "region": "<state_or_region>",
            "country": "<country_code>",
            "postal_code": "<postal_code>",
            "phone_number": "<phone_number>"
          }
        },
        "total_price":  { 
            amount: <pre-order total price>,
            currency: <price currency> 
        },
        "discounts": <array_of_discount_objects>,
        "items": [{
            product_id: <line-item product ID>,
            product_name: <line-item product name>,
            variant_id: <line-item variant ID>,
            sku: <line-item variant SKU>,
            quantity: <line-item quantity>,
            item_price: <price of single item>,
            row_total: <total price of row>, 
        }]
      }
    }
  ],
  "purchases": [{
    email: "<shopper_email>",
    time: "<ISO8601_timestamp>",
    currency: <pre_order currency>,

    product_id:  <line-item product ID>,
    product_name: <line-item product name>,
    variant_id: <line-item variant ID>,
    sku:<line-item variant SKU>,
    quantity:  <line-item quantity>,
    price: <price of single item>,
  }]
}
```


# Converge integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled Converge tracking from the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), then Purple Dot checkout will send the following event (with your desired event name) to your Converge account.

```
event_name:
  '<Your custom event>',
distinct_id: [`urn:email:<Shopper's email>`],
gateway: 'Purple Dot',
properties: {
  id: <Purple Dot pre-order reference>,
  total_price: <total pre-order amount>,
  total_tax: <total pre-order tax amount>,
  total_shipping: <total pre-order shipping amount>,
  total_discount: <total pre-order discount amount>,
  currency: <pre-order currency>,
  coupon: <pre-order discount coupon>,
  items: <Array{
    product_id: <line-item product ID>,
    variant_id: <line-item variant ID>,
    name: <line-item product name>,
    variant_name: <line-item variant name>,
    sku: <line-item variant SKU>,
    price: <line-item price>,
    currency: <pre-order currency>,
    quantity: <line-item quantity>,
    discount: <line-item discount amount>,
  }>,
  profile_properties: {
    $email: <Shopper's email>,
    $phone_number: <Shopper's phone number>,
    $city: <Shopper's city>,
    $state: <Shopper's state>,
    $zip_code: <Shopper's zip code>,
    $countryCode: <Shopper's country code>,
    $first_name: <Shopper's first name>,
    $last_name: <Shopper's last name>,
  }
}
```


# Google Ads

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If your store has Google tags enabled in the theme and you enabled the Google Ads integration on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), then the Purple Dot checkout will forward the `conversion` event to Google Ads.

This is a client side integration.

```
send_to: <the provided Measurement ID>,
value: <total pre-order amount>,
currency: <currency shopper paid in>,
transaction_id: <Purple Dot pre-order reference>,
```


# Google Analytics

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled Google Analytics tracking on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), the Purple Dot checkout automatically sends certain events to Google Analytics 4 via the [Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/ga4).

#### **What you need before you start**

* A **Google Analytics 4** property for the store
* The GA4 **Google tag** active on the storefront (for example via the [Google & YouTube](https://apps.shopify.com/google) Shopify app, Google Tag Manager, or a theme tag), with the `_ga` cookie being set for visitors
* Admin (Editor) access to the merchant’s **Google Analytics** property

**Prerequisites**

Before connecting Purple Dot, the GA4 tag must already be running on the Shopify storefront. Purple Dot will not send any server-side events for a session where it cannot find the browser `_ga` cookie that GA4 sets (this is used as the Measurement Protocol `client_id`).

> ***Use the same Measurement ID everywhere.** The Measurement ID you enter in Purple Dot must match the GA4 web data stream already collecting storefront browser events. If these don’t match, connection tests may pass but production checkout events won’t stitch to the correct sessions.*

#### **Step 1 - Install the Google & YouTube app on Shopify**

1. In **Shopify Admin**, go to **Settings → Apps and sales channels** (or open the [Google & YouTube app on the Shopify App Store](https://apps.shopify.com/google)).
2. Install **Google & YouTube** (by Google LLC).
3. Open the app and sign in with the Google account that has access to the merchant’s **Google Analytics** property.
4. Connect the Shopify store to the correct Google account / Analytics property.
5. When prompted, set up or connect a **Google Analytics 4** property and web data stream. Use the same Measurement ID you plan to use for Measurement Protocol and Purple Dot.
6. Complete the app setup and confirm the Google tag is **connected** and **active** on the storefront.

> ***Use the same Measurement ID everywhere.*** *The Measurement ID you enter in Purple Dot must match the GA4 web data stream connected in the Google & YouTube app and shown in Google Analytics. If these don’t match, connection tests may pass but production events will go to the wrong property—or checkout events won’t attribute correctly.*

**Verify the tag is working on the storefront**

1. In **Shopify Admin**, go to **Settings → Customer events**
2. Verify the app is “Connected”
3. On the **Google & YouTube** app, click “Test”

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FiZG9RmUZXMxmeDuZ7ma7%2Fimage.png?alt=media&amp;token=8ef34d6a-676f-4a3d-a64d-14615c98a377" alt=""><figcaption></figcaption></figure>

1. Accept any **cookie consent** banner that covers analytics cookies.
2. Confirm events are being processed
3. In GA4, open **Reports → Realtime** and confirm storefront page views are arriving.

#### **Step 2 - Find the Measurement ID and create an API Secret**

**Find the Measurement ID**

1. Open [Google Analytics](https://analytics.google.com/).
2. Go to **Admin → Data streams**.
3. Open the **Web** data stream used on the storefront.
4. Copy the **Measurement ID** (format `G-XXXXXXXX`).

Use this value in Purple Dot’s **Measurement ID** field.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F46XmYU1S7xF30FYZNd4q%2Fimage.png?alt=media&amp;token=182afadd-121e-43e8-9451-82ffe93f465a" alt=""><figcaption></figcaption></figure>

**Create a Measurement Protocol API Secret**

1. Stay on the same data stream.
2. Open **Measurement Protocol API secrets**.
3. Click **Create**, give it a nickname such as `Purple Dot`, and create the secret.
4. Copy the **Secret value** immediately and store it securely.

This secret is what Purple Dot calls **API Secret**.

You must have **Editor** (or higher) permission on the GA4 property to create API secrets.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FMsKqwYgpGa2JlQWNW3Qw%2Fimage.png?alt=media&amp;token=0aca825f-b79d-4074-9d08-c1ca6f1b4f59" alt=""><figcaption></figcaption></figure>

#### **Step 3 - Add credentials in Purple Dot**

1. Log in to the **Purple Dot** [**Merchant Portal**](https://www.purpledotprice.com/merchant-portal/settings/integrations).
2. Go to **Settings → Integrations**.
3. Under **Analytics**, click **Connect** for **Google Analytics**.
4. In the Google Analytics connection modal, enter:

   | **Field**          | **Value**                  |
   | ------------------ | -------------------------- |
   | **Measurement ID** | Measurement ID from Step 2 |
   | **API Secret**     | API Secret from Step 2     |
5. Click **Save**.

After the connection is saved, Purple Dot sends real server events automatically when a Google Analytics connection exists for the store.

| Checkout / preorder action | GA4 event name     |
| -------------------------- | ------------------ |
| Add to cart                | `add_to_cart`      |
| Initiate checkout          | `begin_checkout`   |
| Add payment info           | `add_payment_info` |
| Pre-order created          | `purchase`         |

Events include ecommerce fields such as `currency`, `value`, and `items`. Purchase events also include a `transaction_id` (the Purple Dot pre-order / checkout id). When available, Purple Dot also forwards `session_id` (from the `_ga_` session cookie) and Google click identifiers (`gclid` / `gbraid` / `wbraid`) so server events can attribute correctly.

#### **Step 4 - Verify the connection**

There are two ways to verify the integration. Use **Option A** for a quick credential check, **Option B** to test the full checkout flow end-to-end.

**Option A - Test Connection in the modal (recommended for first setup)**

1. In the Google Analytics connection modal, fill in **Measurement ID** and **API Secret**.
2. Click **Test Connection** (bottom-left of the modal).
3. Wait for **“Credentials verified!”**

Purple Dot sends a dedicated validation event to Google’s Measurement Protocol debug endpoint:

* **Event name:** `purple_dot_test`
* **Client ID:** `555.555`

This confirms the Measurement ID and API Secret are accepted by Google. The debug endpoint validates the payload; it is not the same as a storefront checkout event.

**Option B - Test via live checkout (end-to-end)**

This option verifies the full integration: storefront → Purple Dot checkout → GA4 Measurement Protocol → Realtime reporting.

1. Open the storefront and accept cookie consent so the `_ga` cookie is set.
2. In GA4, open **Reports → Realtime** (keep this tab open).
3. Complete a test pre-order/checkout flow (add to cart, open checkout, enter payment details, complete the order).
4. In **Realtime**, confirm the checkout events appear — for example `add_to_cart`, `begin_checkout`, `add_payment_info`, and `purchase`.

> ***Tip:** Server events are only sent when Purple Dot can read a GA4 `client_id` from the storefront `_ga` cookie. If Realtime stays empty after a test checkout, re-check cookie consent and that the Measurement ID in Purple Dot matches the storefront data stream.*


# Klaviyo integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled Klaviyo tracking on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), then Purple Dot checkout can do 3 different things with Klaviyo:

* track checkout conversion, by automatically sending an event (default name is `Placed Pre-Order` but you may change it) to your Klaviyo project whenever a pre-order purchase completes. See event payload example below
* subscribe shoppers to email marketing
* subscribe shoppers to SMS marketing

This is all done server side to ensure that every checkout is tracked.

See [this FAQ](https://purple-dot.support.site/article/how-to-use-klaviyo-with-purple-dot) to learn more.

```
type: 'event',
attributes: {
  profile: {
    data: {
      type: 'profile',
      attributes: {
        email: <shopper's email address>,
        first_name: <shopper's first name>,
        last_name: <shopper's last name>,
        location: {
          address1: <first line of shipping address>,
          address2: <second line of shipping address>,
          city: <shipping address city>,
          region: <shipping address region>,
          country: <shipping address country>,
          zip: <shipping address zip>,
        },
        phone_number: <shopper's phone number>,
      },
    },
  },
  metric: {
    data: {
      type: 'metric',
      attributes: {
        name: <as configured in the Purple Dot dashboard>,
      },
    },
  },
  properties: {
    OrderId: <Purple Dot pre-order reference>,
    ItemNames: [ProductName],
    Items: [{
      Cancelled: <if this line item is now cancelled>,
      ProductName: <name of the product>,
      ProductID: <external ID of this product>,
      VariantID: <external ID of the specific variant purchased>,
      SKU: <sku code of the specific variant purchased>,
      Quantity: <how many units were purchased>,
      ItemPrice: <unit price>,
      RowTotal: <line item total>,
      ShippingGroupID: <Purple Dot ID of the shipping group for this line item>,
    }],
    ShippingGroups: [{
      ShippingGroupID: <Purple Dot ID of this shipping group>,
      Title: <shipping gropu name>,
      Code: <shipping group code>,
      ItemPrice: <shipping group price>,
      RowTotal: <shipping group total>,
    }],
    Discounts: [{
      Type: <type of discount used>,
      Code: <discount code>,
      Amount: <total amount off>,
    }],
  },
  value: <total pre-order amount>,
  value_currency: <currency shopper paid in>,
  time: <date and time this pre-order was placed>,
  unique_id: <Purple Dot pre-order reference>,
}
```


# Meta integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled Meta tracking on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), the Purple Dot checkout automatically sends certain events to Meta via the [Conversions API (CAPI)](https://developers.facebook.com/documentation/ads-commerce/conversions-api).

#### **What you need before you start** <a href="#what-you-need-before-you-start" id="what-you-need-before-you-start"></a>

* The **Facebook & Instagram** app installed on the Shopify store and connected to the merchant’s Meta Business account
* A **dataset (pixel)** active on the storefront via that app, with browser events flowing in Events Manager
* Admin access to the merchant’s **Meta Business Manager** and **Events Manager**

#### **Prerequisites** <a href="#prerequisites" id="prerequisites"></a>

Before configuring Conversions API in Meta or connecting Purple Dot to your Meta account, you must have the **Meta Pixel running on their Shopify storefront**. Purple Dot will not send any server-side events for a session where we could not find browser cookies (`_fbp` and `_fbc`) that the pixel sets in your storefront.

#### **Step 1 - Install the Facebook & Instagram app on Shopify**

1. In **Shopify Admin**, go to **Settings → Customer events** (or open the [Shopify App Store](https://apps.shopify.com/facebook)).
2. Search for and install **Facebook & Instagram** (by Meta).
3. Open the app and sign in with the Meta account that has access to the merchant’s **Business Manager**.
4. Connect the Shopify store to the correct **Meta Business Portfolio** (Business Manager).
5. When prompted, connect or create a **dataset** (Meta Pixel). Use the same dataset you plan to use for Conversions API and Purple Dot.
6. Complete the app setup and confirm the pixel is **connected** and **active** on the storefront.

*Facebook & Instagram app connected to Meta account*

> ***Use the same dataset everywhere.** The Dataset ID you enter in Purple Dot must match the dataset connected in the Facebook & Instagram app and shown in Meta Events Manager. If these don’t match, connection tests may pass but production events will go to the wrong dataset or checkout events won’t attribute correctly.*

**Verify the pixel is working on the storefront**

1. In **Shopify Admin**, go to **Settings → Customer events**
2. Verify the app is “Connected”
3. On the **Facebook & Instagram** app, click “Test”

<figure><img src="https://prod-uk-services-workspac-workspacefilespublicbuck-vs4gjqpqjkh6.s3.amazonaws.com/w_01KQDCFP4WHGWTXXYF884DZJX8/wFile_01KWQDTWG8VYP2Q9XCDW11ZQPK" alt="image.png"><figcaption></figcaption></figure>

1. Accept any **cookie consent** banner that covers marketing/analytics cookies
2. Confirm events are being processed

<figure><img src="https://prod-uk-services-workspac-workspacefilespublicbuck-vs4gjqpqjkh6.s3.amazonaws.com/w_01KQDCFP4WHGWTXXYF884DZJX8/wFile_01KWQDV4HY3JNAVAC1FRERYYVN" alt="image.png" width="563"><figcaption></figcaption></figure>

#### **Step 2 - Set up the Conversions API connection in Meta** <a href="#step-1-set-up-the-conversions-api-connection-in-meta" id="step-1-set-up-the-conversions-api-connection-in-meta"></a>

1. Open [Meta Events Manager](https://business.facebook.com/events_manager).
2. Select the **dataset** used on the merchant’s storefront (the same one connected via the Facebook & Instagram app).
3. Go to **Settings** (gear icon) → **Conversions API**.
4. Choose **Set up manually** or **Connect via partner** (either works; Purple Dot sends events directly with an access token).
5. Review the event configuration. Purple Dot sends these **standard Meta events**:

   | **Purple Dot action**   | **Meta event name** |
   | ----------------------- | ------------------- |
   | Item added to cart      | `AddToCart`         |
   | Checkout started        | `InitiateCheckout`  |
   | Payment details entered | `AddPaymentInfo`    |
   | Pre-order completed     | `Purchase`          |
6. Confirm the dataset is configured to accept server events for those event types.
7. Configure the parameters to send with the events
   1. Event ID
   2. Email
   3. Browser ID
   4. Phone
   5. Client IP

<figure><img src="https://prod-uk-services-workspac-workspacefilespublicbuck-vs4gjqpqjkh6.s3.amazonaws.com/w_01KQDCFP4WHGWTXXYF884DZJX8/wFile_01KWQDVKPQN00MCJKD5EHKWZ1N" alt="image.png" width="563"><figcaption></figcaption></figure>

#### **Step 3 - Generate an access token, get the Dataset ID, and open Test Events** <a href="#step-2-generate-an-access-token-get-the-dataset-id-and-open-test-events" id="step-2-generate-an-access-token-get-the-dataset-id-and-open-test-events"></a>

**Generate an access token**

1. In Events Manager, on the same dataset, go to **Settings → Conversions API**.
2. Under **Set up manually**, find **Generate access token** (or **Set up with Conversions API** → token section).
3. Click **Generate access token**.
4. Copy the token immediately and store it securely. Meta may not show it again.

<figure><img src="https://prod-uk-services-workspac-workspacefilespublicbuck-vs4gjqpqjkh6.s3.amazonaws.com/w_01KQDCFP4WHGWTXXYF884DZJX8/wFile_01KWQDVXDA7SCMCWRG3QKDH8DR" alt="image.png" width="563"><figcaption></figcaption></figure>

**Find the Dataset ID**

1. Stay on the dataset in Events Manager.
2. Open **Settings**.
3. Copy the **Dataset ID** (numeric string, e.g. `1695925551723490`).

<figure><img src="https://prod-uk-services-workspac-workspacefilespublicbuck-vs4gjqpqjkh6.s3.amazonaws.com/w_01KQDCFP4WHGWTXXYF884DZJX8/wFile_01KWQDW5917DNY2EFGZFSSDDEN" alt="image.png" width="563"><figcaption></figcaption></figure>

Use this value in Purple Dot’s **Dataset ID** field (not the Business Manager ID or ad account ID).

**Open Test Events (for verification)**

1. In Events Manager, select the dataset.
2. Open the **Test Events** tab.
3. Copy the **Test event code** shown at the top (e.g. `TEST52433`). You’ll use this when testing from Purple Dot so events appear in this tab instead of production reporting.

Keep this tab open while you run the connection test in Step 5.

#### **Step 4 - Add credentials in Purple Dot** <a href="#step-3-add-credentials-in-purple-dot" id="step-3-add-credentials-in-purple-dot"></a>

1. Log in to the **Purple Dot merchant portal**.
2. Go to **Settings → Integrations**.
3. Under **Analytics**, click **Connect** for **Meta**.
4. In the Meta connection modal, enter:

   | **Field**        | **Value**              |
   | ---------------- | ---------------------- |
   | **Access Token** | Token from Step 3      |
   | **Dataset ID**   | Dataset ID from Step 3 |
5. Click **Save**.

#### **Step 5 - Send a test event and verify the connection** <a href="#step-4-send-a-test-event-and-verify-the-connection" id="step-4-send-a-test-event-and-verify-the-connection"></a>

You can verify in two ways. Use **Test Connection** in the modal for the first setup; use the **Test** button on the saved connection tile for later checks.

**Option A - Test before saving (recommended for first setup)**

1. In the Meta connection modal, fill in **Access Token**, **Dataset ID**, and **Test Event Code**.
2. Click **Test Connection** (bottom-left of the modal).
3. Wait for **“Credentials verified!”**

**Confirm in Meta Events Manager**

1. Return to **Events Manager → \[your dataset] → Test Events**.
2. Within a few seconds, you should see an event named `PurpleDotTestEvent`.
3. Confirm the event shows as received/processed (not rejected).

<figure><img src="https://prod-uk-services-workspac-workspacefilespublicbuck-vs4gjqpqjkh6.s3.amazonaws.com/w_01KQDCFP4WHGWTXXYF884DZJX8/wFile_01KWQDWJHQ436PNJ7C0M0EJDFT" alt="image.png"><figcaption></figcaption></figure>

**Option B - Test via live checkout with `meta_test_event_code` (end-to-end)**

This option verifies the full integration: storefront → Purple Dot checkout → Meta CAPI → Events Manager Test Events. It is the best way to confirm real checkout events (`AddToCart`, `InitiateCheckout`, `AddPaymentInfo`, `Purchase`) are flowing correctly.

1. Copy the **Test event code** from **Meta Events Manager → \[your dataset] → Test Events**.
2. Open the storefront with the test event code in the URL:

   `https://your-store.com/products/example-product?meta_test_event_code=TEST52433`

   Replace `TEST52433` with your actual test event code. The parameter can be added to any storefront page URL.
3. Complete a test pre-order/checkout flow (add to cart, open checkout, enter payment details, complete the order).
4. In **Meta Events Manager → Test Events**, confirm the real checkout events appear - for example `InitiateCheckout`, `AddPaymentInfo`, and `Purchase`.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FIRwwWsMs98p3RUA0BmdN%2Fimage.png?alt=media&amp;token=18073a63-11bc-403a-8a42-3ab142c55532" alt=""><figcaption></figcaption></figure>


# Northbeam integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If your store has Northbeam tracking enabled in the theme and you enabled the Northbeam integration on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), then the Purple Dot checkout will trigger `firePurchaseEvent` to send transaction information to Northbeam.

This is a client side integration.

```
id: <Purple Dot pre-order reference>
totalPrice: <total pre-order amount>,
shippingPrice: <total shipping cost>,
taxPrice: <total tax>,
coupons: <discount code>,
currency: <currency shopper paid in>,
lineItems: [
   {
       productId: <line item product ID>,
       variantId: <line item variant ID>,
       productName: <line item name>,
       variantName: <line item SKU>,
       price: <line item price>,
       quantity: <how many units of this line item>
   }
]
```


# TikTok integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled TikTok tracking on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), the Purple Dot checkout automatically sends certain events to TikTok via the [Events API](https://ads.tiktok.com/help/article/events-api).

### **What you need before you start**

* The [**TikTok**](https://apps.shopify.com/tiktok) app installed on the Shopify store and connected to the merchant’s TikTok Ads account
* A **TikTok Pixel** active on the storefront via that app, with browser events flowing in TikTok Events Manager
* Admin access to the merchant’s **TikTok Ads Manager** / **Events Manager**

### **Step 1 - Install the TikTok app on Shopify**

1. In **Shopify Admin**, go to **Settings → Apps and sales channels** (or open the [TikTok app on the Shopify App Store](https://apps.shopify.com/tiktok)).
2. Install **TikTok** (by TikTok Inc.).
3. Open the app and sign in with the TikTok account that has access to the merchant’s **TikTok Ads Manager**.
4. Connect the Shopify store to the correct **TikTok Ads account**.
5. When prompted, set up or connect a **TikTok Pixel**. The app supports one-click pixel integration — use the same pixel you plan to use for Events API and Purple Dot.
6. Complete the app setup and confirm the pixel is **connected** and **active** on the storefront.

> ***Use the same pixel everywhere.** The Pixel ID you enter in Purple Dot must match the pixel connected in the TikTok Shopify app and shown in TikTok Events Manager. If these don’t match, connection tests may pass but production events will go to the wrong pixel—or checkout events won’t attribute correctly.*

#### **Verify the pixel is working on the storefront**

1. In **Shopify Admin**, go to **Settings → Customer events**
2. Verify the app is “Connected”
3. On the TikTok app, click “Test”

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FBl4rZcU2TpHoyr6fOei1%2Fimage.png?alt=media&amp;token=362f63b8-f35f-460b-b235-00b4c86a5143" alt="" width="375"><figcaption></figcaption></figure>

1. Accept any **cookie consent** banner that covers marketing/analytics cookies
2. Confirm events are being processed

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FoGRgZdufN8SjyArvpBfA%2Fimage.png?alt=media&amp;token=5d835d55-5cbc-4db1-a21e-6c4d97e8091a" alt="" width="375"><figcaption></figcaption></figure>

After the connection is saved, Purple Dot will send real server events automatically when a TikTok connection exists for the store. No extra configuration is required in Purple Dot beyond saving the connection

| Checkout / preorder action | TikTok event name  |
| -------------------------- | ------------------ |
| Add to cart                | `AddToCart`        |
| Initiate checkout          | `InitiateCheckout` |
| Add payment info           | `AddPaymentInfo`   |
| Pre-order created          | `Purchase`         |

### **Step 2 - Generate an access token, get the Pixel ID, and open Test Events**

#### **Generate an access token**

1. In Events Manager, on the same pixel, go to **Settings → Events API**.
2. Generate a new access token
3. Copy the token immediately and store it securely.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F3xWbauPK7VozHFuYml7F%2Fimage.png?alt=media&amp;token=57496334-fede-4d9c-8fb8-5bf20cb04592" alt=""><figcaption></figcaption></figure>

This token is what Purple Dot calls **Access Token**.

#### **Find the Pixel ID**

1. Stay on the pixel in Events Manager.
2. Open **Settings** (or the pixel overview).
3. Copy the **Pixel ID** (alphanumeric string).

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F6mzB4QY50bH4MDXpyfJh%2Fimage.png?alt=media&amp;token=e86a3a1a-1837-4f1b-b730-0fda53ca6073" alt="" width="375"><figcaption></figcaption></figure>

Use this value in Purple Dot’s **Pixel ID** field.

#### **Open Test Events (for verification)**

1. In Events Manager, select the pixel.
2. Open the **Test Events** tab (or **Test event** section).
3. Copy the **Test event code** shown there. You’ll use this when testing from Purple Dot or on the storefront so events appear in this tab instead of production reporting.

Keep this tab open while you run any of the verification options in Step 3.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2Fpgrz8tKZvbpUdMEPUG2K%2Fimage.png?alt=media&amp;token=652d2b58-0175-47d6-befe-92959f15dd13" alt=""><figcaption></figcaption></figure>

### **Step 3 - Add credentials in Purple Dot**

1. Log in to the **Purple Dot merchant portal**.
2. Go to **Settings → Integrations**.
3. Under **Analytics**, click **Connect** for **TikTok**.
4. In the TikTok connection modal, enter:

   | **Field**                        | **Value**                                |
   | -------------------------------- | ---------------------------------------- |
   | **Access Token**                 | Token from Step 2                        |
   | **Pixel ID**                     | Pixel ID from Step 2                     |
   | **Test Event Code** *(optional)* | Test event code from the Test Events tab |
5. Click **Save**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FWhFjNTEt8lVHZcjmfVuZ%2Fimage.png?alt=media&amp;token=6f9c5dda-2017-497a-ba3b-a01753f78e79" alt="" width="563"><figcaption></figcaption></figure>

### **Step 4 - Verify the connection**

There are two ways to verify the integration. Use **Option A** for a quick credential check, **Option B** to test the full checkout flow end-to-end.

#### **Option A - Test Connection in the modal (recommended for first setup)**

1. In the TikTok connection modal, fill in **Access Token**, **Pixel ID**, and **Test Event Code**.
2. Click **Test Connection** (bottom-left of the modal).
3. Wait for **“Credentials verified!”**

Purple Dot sends a dedicated test event:

* **Event name:** `PurpleDotTestEvent`
* **External ID:** `purple-dot-connection-test` (hashed)

If a **Test Event Code** was provided, TikTok routes the event to the **Test Events** tab.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FHcwcJmRnMi7z5nl4vTHY%2Fimage.png?alt=media&amp;token=284298bc-99fb-4fc8-898d-e62b3031fd12" alt="" width="563"><figcaption></figcaption></figure>

#### **Option B - Test via live checkout with `tiktok_test_event_code` (end-to-end)**

This option verifies the full integration: storefront → Purple Dot checkout → TikTok Events API → Events Manager Test Events. It is the best way to confirm real checkout events (`AddToCart`, `InitiateCheckout`, `AddPaymentInfo`, `Purchase`) are flowing correctly.

1. Copy the **Test event code** from **TikTok Events Manager → \[your pixel] → Test Events**.
2. Open the storefront with the test event code in the URL:

   <https://your-store.com/products/example-product?tiktok_test_event_code=YOUR_TEST_CODE>

   Replace `YOUR_TEST_CODE` with your actual test event code. The parameter can be added to any storefront page URL.
3. Accept cookie consent so the `_ttp` cookie is set.
4. Complete a test preorder/checkout flow (add to cart, open checkout, enter payment details, complete the order).
5. In **TikTok Events Manager → Test Events**, confirm the real checkout events appear — for example `AddToCart`, `InitiateCheckout`, `AddPaymentInfo`, and `Purchase`.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FhVd1wsOPQzcbHEtu6xbQ%2Fimage.png?alt=media&amp;token=ca9f4b03-14b2-40e1-8dfa-d3d789b164da" alt="" width="563"><figcaption></figcaption></figure>

#### **How it works**

* Purple Dot reads `tiktok_test_event_code` from the storefront URL.
* The code is stored for the **browser session** (until the tab is closed), so it persists as the shopper navigates and opens embedded checkout.
* For that session, all TikTok server events sent by Purple Dot include the test event code and appear in the **Test Events** tab rather than production reporting.

> ***Tip:** To stop sending test events, close the browser tab (or open a new session without the query parameter). The test event code is not persisted beyond the browser session.*


# TripleWhale integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If you have enabled TripleWhale tracking on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), the Purple Dot checkout automatically maps mid-funnel milestones (such as starting a checkout) and final purchase actions to Triple Whale via the [Data-In API](https://kb.triplewhale.com/en/articles/10371684-understanding-triple-whale-s-data-in-feature), ensuring that your preorder revenue and funnel conversions are attributed to the correct marketing channels.

### What you need before you start

* A **Triple Whale account** active and connected to your Shopify store.
* The **Triple Pixel** installed and actively tracking your storefront browser sessions.
  * [Shopify App Store](https://apps.shopify.com/triplewhale-1?st_source=autocomplete\&surface_detail=autocomplete_apps)
* **Admin / Developer access** to your Triple Whale dashboard to generate API keys.

### Step 1 - Generate an API Key in Triple Whale

* [Triple Whale - Creating and Managing API Keys](https://kb.triplewhale.com/en/articles/8116412-creating-and-managing-api-keys)

Triple Whale secures data ingestion via scoped API Keys. You must generate a key that specifically allows Purple Dot to write order details to your account.

1. Log into your **Triple Whale Dashboard**.
2. Navigate to **Data** → **APIs**.
3. Click **Generate** to create a new API Key.
4. Fill in the configuration details:
   * **Description:** Enter `Purple Dot Integration`.
   * **Required Scopes:** Select **`Orders: Write`**
5. Click **Generate API Key**.
6. **Copy the API Key immediately** and store it securely. Triple Whale will only show this full string once.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FigdKCVmkA9eYwxVs5x3V%2Fimage.png?alt=media&amp;token=c997383b-e29e-4a78-af20-523515ee1de0" alt="" width="375"><figcaption></figcaption></figure>

### Step 2 - Add Credentials in Purple Dot

Fetch your store domain as configured in Triple Whale

1. Log into the **Triple Whale dashboard**
2. Go to **Settings → Store**
3. Copy the **domain** on the store details

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FeMpA86K1hW7MzRKEfYbH%2Fimage.png?alt=media&amp;token=043a7c02-0e36-4cf7-9f31-5023941ca960" alt="" width="375"><figcaption></figcaption></figure>

1. Log in to the **Purple Dot merchant portal**.
2. Go to **Settings → Integrations**.
3. Under **Analytics**, click **Connect** for **Triple Whale**.
4. In the Triple Whale connection modal, enter:

| Field           | Value                                             |
| --------------- | ------------------------------------------------- |
| **API Key**     | Paste the secure API Key generated in **Step 1**. |
| **Shop Domain** | Enter your permanent Shopify domain.              |

**This must match the domain configured in TripleWhale**. |

1. Click **Save**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FePECtoF17MAdg7oBsTQD%2Fimage.png?alt=media&amp;token=a84ff4ea-555a-4d8e-833a-18f104ce42e9" alt="" width="375"><figcaption></figcaption></figure>

Once the connection is saved, Purple Dot passes events automatically when checkout milestones are triggered:

| Purple Dot action                 | Triple Whale Data-In Layer                                  | Expected Processing Speed  |
| --------------------------------- | ----------------------------------------------------------- | -------------------------- |
| **Initiate Checkout**             | Data Enrichment for Pixel Attribution (`initiate_checkout`) | Appears inside \~5 minutes |
| **Add Payment Info**              | Data Enrichment for Pixel Attribution (`add_payment_info`)  | Appears inside \~5 minutes |
| **Pre-order Created / Completed** | Custom Sales Platform Ingestion (`/data-in/orders`)         | Appears inside \~5 minutes |

### Step 3 - Verify the Connection & Test Events

Because Triple Whale processes server-side API entries dynamically, incoming events do not stream into a real-time visual "sandbox console." Instead, you can verify your integration using built-in account diagnostic tools.

#### Option A - Check the Custom Account Health Page (Quick Check)

Triple Whale offers a live tracker showing exactly when data packets last arrived.

1. Complete a test checkout flow using your Purple Dot embedded checkout.
2. Inside Triple Whale, navigate to your **Custom Account Health** page.
3. Check the **Orders API** and **Pixel** sections. If the connection is successful, the card will instantly update from *"Not Installed"* to showing the total event count received in the last 24 hours, alongside a **"Last order received: Just Now"** timestamp.

#### Option B - Run a Diagnostic Query in the SQL Editor (Deep Dive)

To confirm that your checkout events (`initiate_checkout`) and final pre-orders are passing the exact customer fields and metadata fields correctly:

1. Go to the **SQL Editor** tab inside your Triple Whale dashboard.
2. Run a simple query to see the most recent incoming records:

```sql
SELECT * FROM orders_table 
WHERE event_date = CURRENT_DATE() 
ORDER BY created_at DESC 
LIMIT 5
```

### Excluding Released Orders from Triple Whale (Preventing Double Counting)

A **Purchase** event is recorded in Triple Whale the exact moment a shopper completes a pre-order via the Purple Dot checkout. Later, when you officially release that pre-order for fulfillment, Purple Dot automatically creates a corresponding order inside Shopify.

Because Triple Whale automatically ingests all new Shopify orders, **this will lead to double-counting your revenue** if it isn't filtered out.

To resolve this and keep your financial data accurate, you must configure a Global Filter in Triple Whale to ignore these released Shopify orders:

* [Triple Whale Global Filters](https://kb.triplewhale.com/en/articles/11386505-global-filters)

#### How to Configure the Global Filter

1. Log into your **Triple Whale** dashboard.
2. Navigate to **Settings** (gear icon) > **Integrations** > **Shopify**.
3. Locate the **Order Filters** or **Global Exclusions** section.
4. Add a new filter rule based on your Purple Dot tags:
   * **Filter Type:** Order Tag
   * **Condition:** Contains
   * **Value:** `purple dot`
5. Click **Save Changes**.

> ⚠️ **Important:** Once this filter is applied, Triple Whale will continue to count the original pre-order revenue captured by Purple Dot on day one, but it will safely ignore the secondary fulfillment duplicate order generated later by Shopify.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FDTkSrENFIOZME3tR9ihl%2Fimage.png?alt=media&amp;token=436a22cb-a14d-4032-b590-f68dfc6f9b29" alt="" width="375"><figcaption></figcaption></figure>


# Yotpo integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout. Pre-orders sold through the Shopify checkout benefit from the same tracking as your regular sales.
{% endhint %}

If your store has Yotpo tracking enabled in the theme and you have enabled the Yotpo tracking on the Integration settings page in the [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations), the Purple Dot checkout will forward order information to Yotpo.

This is a client side integration.

```
source: 'pixel_v2',
platform: 'shopify',
orderId: <Purple Dot pre-order reference>,
orderNumber: <Purple Dot pre-order reference>,
orderName: <Purple Dot pre-order reference>,
orderAmount: <total pre-order amount>,
orderCurrency: <currency shopper paid in>,
```


# Custom client side tracking integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout.
{% endhint %}

Purple Dot dispatches several `CustomEvent` objects on the `window` object. These events can be used to track user interactions, monitor conversions, and integrate with analytics platforms like Google Analytics in a custom way.

To listen for these events, use the following pattern:

```
window.addEventListener('PurpleDot:<EventName>', (event) => {
  console.log('Event received:', event.detail);
  // Your custom logic here
});
```

#### PurpleDot:Ready

This is fired when the Purple Dot SDK is ready and initialized.

Example:

```
window.addEventListener('PurpleDot:Ready', () => {
  console.log('PurpleDot SDK is ready!');
});
```

#### PurpleDot:LearnMoreClicked

This is fired when a shopper clicks the "Learn More" link on the PDP.

This object contains some useful information:

* `placementType` - The type of placement
* `instanceId` - Unique identifier for this placement instance
* `skuId` - The SKU ID associated with the placement
* `sku` - The SKU object containing product information
* `displayCurrency` - The currency used for display
* `releaseId` - The release ID for this placement

Example:

```
window.addEventListener('PurpleDot:LearnMoreClicked', (event) => {
  console.log('Learn more clicked:', event.detail);

  // Send to GA4
  gtag('event', 'purple_dot_learn_more_clicked', {
    placement_type: event.detail.placementType,
    sku_id: event.detail.skuId,
    currency: event.detail.displayCurrency
  });
});
```

#### PurpleDot:AddToCart

This is fired when a product is added to the cart as a pre-order.

This object contains some useful information:

* `skuId` - Shopify's product variant ID of what got added to the cart
* `internalSkuId` - Purple Dot's own ID for the same, for internal tracking
* `releaseId` - The Waitlist ID for this product
* `price` - The price of the line item
* `quantity` - The quantity added to cart

Example:

```
window.addEventListener('PurpleDot:AddToCart', (event) => {
  console.log('Added to cart:', event.detail);

  // Send to GA4
  gtag('event', 'add_to_cart', {
    currency: 'USD', // You may need to determine this from context
    value: event.detail.price * event.detail.quantity,
    items: [{
      item_id: event.detail.skuId,
      item_name: 'Product', // You may need to get this from your product data
      quantity: event.detail.quantity,
      price: event.detail.price
    }]
  });
});
```

#### PurpleDot:RemoveFromCart

This is fired when line items are removed from the cart.

This object contains some useful information:

* `lineItems` - Array of line items in the cart
* `shipping` - Shipping information
* `shippingAddress` - Shipping address details
* `email` - Customer email
* `total` - Total cart value
* `tax` - Tax amount
* `discountCode` - Applied discount code
* `checkoutState` - Current state of checkout

Example:

```
window.addEventListener('PurpleDot:RemoveFromCart', (event) => {
  console.log('Removed from cart:', event.detail);

  // Send to GA4
  gtag('event', 'remove_from_cart', {
    currency: 'USD',
    value: event.detail.total,
    items: event.detail.lineItems
  });
});
```

#### PurpleDot:CheckoutLoaded

This is fired when the Purple Dot checkout interface is loaded.

This object contains some useful information:

* `enableCombinedCart` - Whether combined cart functionality is enabled

Example:

```
window.addEventListener('PurpleDot:CheckoutLoaded', (event) => {
  console.log('Checkout loaded:', event.detail);

  // Send to GA4
  gtag('event', 'purple_dot_checkout_loaded', {
    combined_cart_enabled: event.detail.enableCombinedCart
  });
});
```

#### PurpleDot:PreorderCheckoutStep

This is fired when a shopper progresses through a step in the pre-order checkout process.

This object contains some useful information:

* `skuId` - The SKU ID for the pre-order
* `stepName` - Name of the current step
* `stepNumber` - Number of the current step
* `releaseId` - The release ID for this pre-order
* `lineItems` - Array of line items
* `shipping` - Shipping information
* `shippingAddress` - Shipping address details
* `email` - Customer email
* `total` - Total order value
* `tax` - Tax amount
* `discountCode` - Applied discount code

Example:

```
window.addEventListener('PurpleDot:PreorderCheckoutStep', (event) => {
  console.log('Preorder checkout step:', event.detail);

  // Send to GA4
  gtag('event', 'purple_dot_preorder_checkout_step', {
    step_name: event.detail.stepName,
    step_number: event.detail.stepNumber,
    sku_id: event.detail.skuId,
    value: event.detail.total
  });
});
```

#### PurpleDot:PreorderCheckoutSubmitted

This is fired when a pre-order checkout form is submitted.

This object contains some useful information:

* `skuId` - The SKU ID for the pre-order
* `releaseId` - The Waitlist ID for this pre-order

Example:

```
window.addEventListener('PurpleDot:PreorderCheckoutSubmitted', (event) => {
  console.log('Preorder checkout submitted:', event.detail);

  // Send to GA4
  gtag('event', 'purple_dot_preorder_checkout_submitted', {
    sku_id: event.detail.skuId
  });
});
```

#### PurpleDot:PreorderCreated

This is fired when a pre-order is successfully created.

This object contains some useful information:

* `reference` - Pre-order reference number
* `email` - Customer email
* `shippingAddress` - Shipping address details
* `lineItems` - Array of line items
* `total` - Total order value
* `shipping` - Shipping information
* `tax` - Tax amount
* `discountCode` - Applied discount code

Example:

```
window.addEventListener('PurpleDot:PreorderCreated', (event) => {
  console.log('Preorder created:', event.detail);

  // Send to GA4
  gtag('event', 'purchase', {
    transaction_id: event.detail.reference,
    value: event.detail.total,
    currency: 'USD',
    items: event.detail.lineItems
  });
});
```


# Custom server side tracking integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout.
{% endhint %}

Purple Dot sends server-side checkout and pre-order events to an HTTPS endpoint you control. Connect it in the Purple Dot [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations) under **Settings → Connections → Analytics** as **Webhook**.

Once connected, Purple Dot automatically sends events as shoppers move through your checkout and when they complete a pre-order. This works with:

* **Google Tag Manager server-side** (GTM SS) - forward events into your server container and on to Meta, Google Ads, TikTok, etc.
* **A custom webhook** - any HTTPS endpoint that accepts JSON `POST` requests.

### **What you need before you start**

* An **HTTPS endpoint** ready to receive events.
  * For **GTM server-side**: your server container URL
  * For a **custom webhook**: a URL on your backend or event router.
* **Optional:** a **Bearer token** if your endpoint requires authentication.

> Your webhook URL **must** use `https://`. HTTP URLs cannot be saved.

### **Step 1 - Set up your receiving endpoint**

Your endpoint must accept `POST` requests with a JSON body and return a **2xx** response to confirm receipt.

#### **Option A - Google Tag Manager server-side (recommended)**

If you use GTM server-side to route events to ad platforms:

1. Open your **server-side GTM container**.
2. Create or identify the **Client** that receives HTTP requests (commonly a **Custom Client** or your host’s default ingest client).
3. Copy the **HTTPS URL** for that client - this is the URL Purple Dot will POST to.
4. In your server container, configure **Tags** and **Triggers** to map incoming Purple Dot events to your ad platform tags (Meta CAPI, Google Ads, TikTok, etc.).

Map Purple Dot `event_name` values to the events your tags expect:

| **Purple Dot `event_name`** | **Typical GTM / ad platform event**    |
| --------------------------- | -------------------------------------- |
| `AddToCart`                 | `add_to_cart`                          |
| `InitiateCheckout`          | `begin_checkout` / `initiate_checkout` |
| `AddPaymentInfo`            | `add_payment_info`                     |
| `Purchase`                  | `purchase`                             |

> Work with your analytics agency or GTM administrator if you are unsure which client URL or tag mapping to use.

#### **Option B - Custom webhook**

If you are building your own integration:

1. Deploy an HTTPS route that accepts `POST` with `Content-Type: application/json`.
2. Parse the JSON body using the **event schema** below.
3. Return **2xx** on success.

If your endpoint uses authentication, configure it to accept:

Authorization: Bearer \<your-token>

Purple Dot only sends this header when a Bearer Token is configured in the connection.

### **Step 2 - Add credentials in Purple Dot**

1. Log in to the **Purple Dot merchant portal**.
2. Go to **Settings → Connections**.
3. Under **Analytics**, click **Connect** for **Webhook**.
4. Enter:

| **Field**        | **Value**                                                                      |
| ---------------- | ------------------------------------------------------------------------------ |
| **Webhook URL**  | Your HTTPS endpoint (GTM server container client URL or custom webhook URL).   |
| **Bearer Token** | *(Optional)* Secret token your endpoint expects in the `Authorization` header. |

1. Click **Save**.

> **What this is:** The Webhook URL is where Purple Dot sends all analytics events. The Bearer Token is stored securely and only sent when you provide one.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F1aGXI03E3Khn5BExb56R%2Fimage.png?alt=media&amp;token=4ba26f9d-d6c0-4552-afc8-c49b521c7b0c" alt=""><figcaption></figcaption></figure>

***

### **Step 3 - Verify the connection and test events**

#### **Option A - Test from the merchant portal (quick check)**

1. In **Settings → Connections**, open your Webhook connection.
2. Click **Test**.
3. Purple Dot sends a `PurpleDotTestEvent` to your endpoint.
4. If your endpoint returns **2xx**, the connection is marked healthy.

**Test event payload:**

```json
{
  "event_name": "PurpleDotTestEvent",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_time": "2024-01-15T12:00:00.000Z"
}
```

#### **Option B - Run a real checkout (deep check)**

1. Complete a test pre-order through your Purple Dot embedded checkout.
2. Confirm your endpoint (or GTM server container preview / request logs) receives:
   * `InitiateCheckout` when checkout starts
   * `AddPaymentInfo` when payment details are submitted
   * `Purchase` when the pre-order is completed

For GTM server-side, use **Preview mode** in your server container to confirm events arrive and your tags fire.

### **What happens in production**

Once the connection is saved, Purple Dot sends events automatically when checkout milestones are triggered:

| **Shopper action**      | **`event_name`**   | **When it fires**               |
| ----------------------- | ------------------ | ------------------------------- |
| **Add to cart**         | `AddToCart`        | Item added in embedded checkout |
| **Initiate checkout**   | `InitiateCheckout` | Checkout session starts         |
| **Add payment info**    | `AddPaymentInfo`   | Payment details submitted       |
| **Pre-order completed** | `Purchase`         | Pre-order successfully created  |

Events are sent server-side shortly after each action. Exact timing depends on background processing, not a fixed delay.

### **Event payload schema**

Every production event is a `POST` with `Content-Type: application/json`.

#### **Request format**

| **Property** | **Value**                                                              |
| ------------ | ---------------------------------------------------------------------- |
| Method       | `POST`                                                                 |
| URL          | Your configured Webhook URL                                            |
| Headers      | `Content-Type: application/json`                                       |
| Auth         | `Authorization: Bearer <token>` *(only if Bearer Token is configured)* |

#### **Event fields**

| **Field**                   | **Type** | **Required** | **Description**                                                                                                                |
| --------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `event_name`                | string   | Yes          | `Purchase`, `AddToCart`, `InitiateCheckout`, or `AddPaymentInfo`                                                               |
| `transaction_id`            | string   | Yes          | Unique ID for the event. On `Purchase`, this is your pre-order reference when available; on funnel events, a session event ID. |
| `event_time`                | string   | Yes          | ISO 8601 timestamp, e.g. `2024-01-15T12:00:00.000Z`                                                                            |
| `user_data`                 | object   | No           | Hashed customer identifiers — see **PII handling**                                                                             |
| `user_data.email`           | string   | No           | SHA-256 hash of customer email                                                                                                 |
| `user_data.phone`           | string   | No           | SHA-256 hash of customer phone                                                                                                 |
| `order`                     | object   | Yes          | Order / cart summary                                                                                                           |
| `order.reference`           | string   | No           | Pre-order reference (usually on `Purchase` only)                                                                               |
| `order.currency`            | string   | Yes          | Currency code, lowercased (e.g. `usd`)                                                                                         |
| `order.value`               | number   | Yes          | Total order value                                                                                                              |
| `order.contents`            | array    | No           | Line items (omitted if empty)                                                                                                  |
| `order.contents[].id`       | string   | Yes          | Product / variant ID (typically your Shopify variant ID)                                                                       |
| `order.contents[].quantity` | number   | Yes          | Quantity                                                                                                                       |
| `order.contents[].amount`   | number   | Yes          | Unit price                                                                                                                     |
| `click_ids`                 | object   | No           | Ad platform click IDs captured during checkout                                                                                 |
| `click_ids.fbc`             | string   | No           | Meta (`_fbc`)                                                                                                                  |
| `click_ids.ttclid`          | string   | No           | TikTok click ID                                                                                                                |
| `click_ids.gclid`           | string   | No           | Google Ads click ID                                                                                                            |
| `click_ids.gbraid`          | string   | No           | Google Ads iOS attribution                                                                                                     |
| `click_ids.wbraid`          | string   | No           | Google Ads web-to-app attribution                                                                                              |

`user_data`, `click_ids`, and `order.contents` are **omitted** when there is nothing to send.

#### **Example `Purchase` event**

```json
{
  "event_name": "Purchase",
  "transaction_id": "998231",
  "event_time": "2024-01-15T12:00:00.000Z",
  "user_data": {
    "email": "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
    "phone": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
  },
  "order": {
    "reference": "998231",
    "currency": "usd",
    "value": 99.5,
    "contents": [
      {
        "id": "45678901234",
        "quantity": 2,
        "amount": 49.75
      }
    ]
  },
  "click_ids": {
    "fbc": "fb.1.1234567890.AbCdEf",
    "gclid": "CjwKCAjw..."
  }
}
```

#### **Example funnel event (`InitiateCheckout`)**

```json
{
  "event_name": "InitiateCheckout",
  "transaction_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_time": "2024-01-15T12:00:00.000Z",
  "order": {
    "currency": "usd",
    "value": 99.5,
    "contents": [
      {
        "id": "45678901234",
        "quantity": 2,
        "amount": 49.75
      }
    ]
  }
}
```

### **PII and customer data**

Purple Dot does **not** send raw email addresses or phone numbers.

When available, customer contact details appear in `user_data` as **SHA-256 hashes** (lowercase hex strings):

| **Field** | **How it is prepared before hashing**                                                    |
| --------- | ---------------------------------------------------------------------------------------- |
| **Email** | Trimmed and lowercased                                                                   |
| **Phone** | Converted to international **E.164** format (using the shopper’s country when available) |

This matches what major ad platforms expect for server-side matching (Meta CAPI, TikTok Events API, Google Ads enhanced conversions, etc.), so you can forward hashed identifiers without Purple Dot transmitting plaintext PII.


# Pre-order Automation

Purple Dot can read your purchase orders to power pre-order automation - matching incoming stock to your Shopify catalog to automate Waitlist creation.

We currently support a number of ERPs:

* [Apparel Magic](https://purple-dot.support.site/article/how-to-use-apparel-magic-with-purple-dot)
* [BrightPearl](https://purple-dot.support.site/article/how-to-use-brightpearl-with-purple-dot)
* [Cin7 Core](https://purple-dot.support.site/article/how-to-use-cin-7-core-with-purple-dot)
* [Cin7 Omni](https://purple-dot.support.site/article/how-to-use-cin-7-omni-with-purple-dot)
* [GoodDay](https://purple-dot.support.site/article/how-to-use-good-day-with-purple-dot)
* [Fulfil.io](https://docs.getpurpledot.com/docs/shopify-stores/pre-order-automation/fulfil.io)
* [Linnworks](https://purple-dot.support.site/article/how-to-use-linnworks-with-purple-dot)
* [Oracle NetSuite](https://docs.getpurpledot.com/docs/shopify-stores/pre-order-automation/oracle-netsuite)


# Oracle NetSuite

Purple Dot can read your NetSuite purchase orders to power pre-order automation - matching incoming stock to your Shopify catalog and creating Waitlists from expected delivery dates.

This guide walks through the one-time NetSuite setup, then connecting your NetSuite account to the Purple Dot [Merchant Portal](https://www.purplhttps//www.purpledotprice.com/merchant-portal/settings/integrations).

### **Before you start**

You will need:

* A NetSuite **administrator** account (to enable features, create roles, and set up the integration)
* Access to the Purple Dot **merchant portal** (Settings → Integrations)

### **Step 1: Find your Account ID**

Your Account ID appears in your NetSuite login URL.

**Example:** if you sign in at `https://123456-sb1.app.netsuite.com`, your Account ID is **`123456-sb1`**.

You can also find it at **Setup → Company → Company Information** → **Company URLs** tab.

**Sandbox accounts** include a suffix such as `-sb1` or `-sb2`. You will need to indicate this when connecting in Purple Dot.

### **Step 2: Enable required NetSuite features**

A NetSuite administrator must enable the following features before anything else will work.

Go to **Setup → Company → Enable Features** → **SuiteCloud** tab.

Enable these (you may need to accept the SuiteCloud Terms of Service):

| **Section**                  | **Feature**       |
| ---------------------------- | ----------------- |
| **SuiteTalk (Web Services)** | REST Web Services |
| **Manage Authentication**    | OAuth 2.0         |

Click **Save**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FPro28ozbK0JGXvojgVto%2Fimage.png?alt=media&amp;token=36344d5d-a5d8-42ec-950e-075a3d52c349" alt=""><figcaption></figcaption></figure>

Go to **Setup → Company → Enable Features** → **Analytics** tab.

Enable these

| Section                 | Feature                 |
| ----------------------- | ----------------------- |
| SuiteAnalytics Workbook | SuiteAnalytics Workbook |

Click **Save**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F5adkMv9R1RNgk9mNfGVS%2Fimage.png?alt=media&amp;token=25af7eaa-4434-4e40-b9be-b1efc6b0f0d1" alt=""><figcaption></figcaption></figure>

### **Step 3: Create an integration role**

Create a dedicated role for Purple Dot. **Do not use the Administrator role** - Purple Dot will not accept it during setup.

Go to **Setup → Users/Roles → Manage Roles → New**.

**Suggested name:** `Purple Dot Integration`

#### **Transactions permissions**

| **Permission**   | **Level** |
| ---------------- | --------- |
| Purchase Order   | View      |
| Find Transaction | View      |

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F70cB2GM633aEsbRhUOQN%2Fimage.png?alt=media&amp;token=6ee72f43-c3d5-4990-9230-eac6363e347e" alt=""><figcaption></figcaption></figure>

#### **Reports permissions**

| **Permission**          | **Level** |
| ----------------------- | --------- |
| SuiteAnalytics Workbook | View      |

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FHFzU5vyrhb13oPCJMdp5%2Fimage.png?alt=media&amp;token=0c9b7c60-492c-4722-b420-3071c1e21609" alt=""><figcaption></figcaption></figure>

#### **Lists permissions**

| **Permission** | **Level** |
| -------------- | --------- |
| Items          | View      |
| Locations      | View      |

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F9dvX152DgJPuUWxPtGmn%2Fimage.png?alt=media&amp;token=7fe248c5-7629-471f-bb69-42f52ad6d9b9" alt=""><figcaption></figcaption></figure>

#### **Setup permissions**

<table data-header-hidden><thead><tr><th width="323.05859375"></th><th></th></tr></thead><tbody><tr><td><strong>Permission</strong></td><td><strong>Level</strong></td></tr><tr><td>Log in using OAuth 2.0 Access Tokens</td><td>Full</td></tr><tr><td>Manage own OAuth 2.0 Client Credentials certificates</td><td>Full</td></tr><tr><td>REST Web Services</td><td>Full</td></tr></tbody></table>

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FEUcDDcgIsYBUICkcCYiV%2FScreenshot%202026-07-20%20at%2016.18.17.png?alt=media&amp;token=a1b35be3-8dbc-4bd2-a6ac-f3336b9f4423" alt=""><figcaption></figcaption></figure>

#### **Leave unchecked**

* **Web Services Only Role**
* **Administrator** - Purple Dot will reject users with Administrator access

Click **Save**.

### **Step 4: Create an integration user**

Create a dedicated NetSuite user for this connection - do not use a personal admin account for day-to-day authorization.

1. Go to **Lists → Employees → Employees → New**
2. Create a user, e.g. `purpledot-integration@yourcompany.com`.
3. On the **Access** tab:
   * Check **Give Access**
   * Set a password (needed for the one-time authorization step)
   * Under **Roles**, assign **only** the `Purple Dot Integration` role
4. Click **Save**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F0mtUYhjwgk6dEFTfINeH%2Fimage.png?alt=media&amp;token=86628831-8125-4201-8ef2-b55183a5628b" alt=""><figcaption></figcaption></figure>

### **Step 5: Create a Purple Dot integration in NetSuite**

A NetSuite administrator creates the integration record that Purple Dot will connect to.

Go to **Setup → Integration → Manage Integrations → New**.

#### **General**

| **Field** | **Value**               |
| --------- | ----------------------- |
| **Name**  | Purple Dot (or similar) |
| **State** | Enabled                 |

#### **Authentication tab**

Under **OAuth 2.0**, enable:

* Authorization Code Grant
* Client Credentials (Machine to Machine) Grant
* **Public Client** - Purple Dot does not require a client secret

Under **Scope**, enable:

* REST Web Services

#### **Redirect URI**

Add the following callback URL

```
<https://www.purpledotprice.com/merchant-portal/connections/netsuite/callback>
```

Copy this URL **exactly** - it must match character for character.

Click **Save**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FBv6ta5q10XnZmI39mfU6%2Fimage.png?alt=media&amp;token=b120707d-afa9-4c8f-8b08-500cce551317" alt=""><figcaption></figcaption></figure>

#### **Copy your Client ID**

After saving, NetSuite displays a **Client ID**. Copy it now - you cannot view it again later.

If you missed it, edit the integration and use **Reset Credentials** to generate a new Client ID.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FsDE6NeT67HIbbB5lLR0a%2Fimage.png?alt=media&amp;token=62ab1027-9f2b-47ae-b9df-0aeabf1c27a6" alt=""><figcaption></figcaption></figure>

### **Step 6: Connect in Purple Dot**

1. In the Purple Dot merchant portal, go to **Settings → Integrations**.
2. Find **NetSuite** and click **Connect**.

#### **Part A - Enter your details**

In the connect modal:

* **Account ID** - from Step 1
* **Client ID** - from Step 5
* **Sandbox account** - check this if your Account ID includes a sandbox suffix (e.g. `sb1`)
* Click **Connect**

Purple Dot will prepare your connection. This usually takes a few seconds.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FLpfdqoCSQfMieEek5p0Q%2Fimage.png?alt=media&amp;token=fc64fc12-c004-4076-83a2-bf1e15affcdc" alt=""><figcaption></figcaption></figure>

#### **Part B - Authorize in NetSuite**

**Important:** Do **NOT** authenticate as an Administrator role. Choose the role you created in Step 3

1. When ready, click **Finish set-up**.
2. Sign in to NetSuite using your **integration user** (from Step 4).
3. On the consent screen:
   * Click **Choose Another Role**
   * Select **Purple Dot Integration** — not Administrator
   * Click **Allow**
4. You will be returned to Purple Dot. NetSuite should now appear under your live integrations.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FEnUtOjrmimunOseLk0KH%2Fimage.png?alt=media&amp;token=cbdbb424-dd5f-4a17-95b5-f8350607e5a2" alt=""><figcaption></figcaption></figure>

### **What happens after you connect**

Once connected, Purple Dot can read your NetSuite purchase orders — including SKUs, quantities, locations, and expected delivery dates — to draft waitlists automatically.

You can configure which locations and purchase orders to include when setting up waitlist automation in Purple Dot.

### **Troubleshooting**

| **Problem**                         | **What to try**                                                                                                                 |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Authorization fails immediately     | Check that the redirect URI in NetSuite matches the URL shown in the Purple Dot wizard exactly                                  |
| "Administrator role cannot be used" | On the NetSuite consent screen, click **Choose Another Role** and select your integration role                                  |
| "Cannot query purchase orders"      | Review the role permissions in Step 3 — especially SuiteAnalytics Workbook, Purchase Order View, Items View, and Locations View |
| Lost your Client ID                 | Edit the integration in NetSuite and reset credentials to generate a new one, then update it in Purple Dot                      |
| Need to start over                  | Use **Start over** in the Purple Dot connect wizard to clear progress and begin again                                           |

### **Checklist**

* \[ ] REST Web Services, OAuth 2.0, and SuiteAnalytics Workbook enabled in NetSuite
* \[ ] Integration role created with the required permissions
* \[ ] Dedicated integration user created with only that role
* \[ ] Integration record created (Enabled, with OAuth grants and REST Web Services scope)
* \[ ] Redirect URI matches Purple Dot exactly
* \[ ] Client ID saved
* \[ ] Connected in Purple Dot and authorization completed with the integration user and role

***

If you get stuck, contact Purple Dot support with your Account ID and a description of where the setup failed.


# Fulfil.io

Purple Dot can connect to your Fulfil account to power pre-order automation - matching incoming stock to your Shopify catalog and creating Waitlists from expected delivery dates.

This guide walks through creating an OAuth app in Fulfil, then connecting it to the Purple Dot [Merchant Portal](https://www.purpledotprice.com/merchant-portal/settings/integrations).

#### **Before you start**

You will need:

* Access to your **Fulfil** account with permission to create OAuth applications (Settings → API / Developer access)
* Access to the Purple Dot **merchant portal** (Settings → Integrations)

Allow 10–15 minutes for the full setup.

#### **Step 1: Find your workspace**

Your workspace is the subdomain in your Fulfil URL.

**Example:** if you sign in at `https://acme.fulfil.io`, your workspace is `acme`.

You will enter this when connecting in Purple Dot.

#### **Step 2: Create an OAuth app in Fulfil**

1. Sign in to Fulfil and go to <https://auth.fulfil.io/user/clients>.
2. Create a new client / OAuth application.
3. Give the app a **name** - e.g. `Purple Dot`.
4. Set the **Redirect URL** to:

```
<https://www.purpledotprice.com/merchant-portal/connections/fulfilio/callback>
```

Copy this URL **exactly** - it must match character for character, or authorization will fail.

1. Save the app.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FTxKOliZbBb0LNpX3dbh3%2Fimage.png?alt=media&amp;token=bcdaf6b6-4ee9-4f63-bf65-10c7d81ca8ab" alt=""><figcaption></figcaption></figure>

#### **Step 3: Copy your Client ID and Client Secret**

After saving, Fulfil displays a **Client ID** and **Client Secret**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FZ5lpjTglwNUUTYwjiHCW%2Fimage.png?alt=media&amp;token=bc1365bf-2d97-4c63-a5a0-acbd553387d0" alt=""><figcaption></figcaption></figure>

#### **Step 4: Connect in Purple Dot**

1. In the Purple Dot merchant portal, go to **Settings → Integrations**.
2. Find [**Fulfil.io**](http://Fulfil.io) and click **Connect**.

**Part A - Enter your details**

In the connect modal:

* **Workspace** - from Step 1 (e.g. `acme`)
* **Client ID** - from Step 3
* **Client Secret** - from Step 3
* Click **Connect**

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FstFVxtQJhnWqsHE7qCgO%2Fimage.png?alt=media&amp;token=d07e0aaf-f844-47eb-a324-e6fec5c2d9cc" alt=""><figcaption></figcaption></figure>

**Part B - Authorize in Fulfil**

1. When ready, click **Finish set-up**.
2. You will be redirected to Fulfil to authorize the Purple Dot app.
3. Approve the requested permissions, click **Allow**.
4. You will be returned to Purple Dot. Fulfil should now appear under your live integrations.

#### **What happens after you connect**

Once connected, Purple Dot can:

* Read your incoming purchase-order and transfer shipments - including SKUs, quantities, locations, and expected delivery dates - to draft Waitlists automatically.
* Match your Fulfil products and sales orders to your Shopify catalog and orders.

Purple Dot uses a single Fulfil connection for both reading data (pre-order automation) and managing shipments (native fulfillment). Here's why each permission is needed.

#### **Troubleshooting**

| **Problem**                        | **What to try**                                                                                                                      |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Authorization fails immediately    | Check that the Redirect URL in Fulfil matches `https://www.purpledotprice.com/merchant-portal/connections/fulfilio/callback` exactly |
| Connection rejected after allowing | You may have unchecked one or more permissions on the consent screen. Start over and leave all permissions enabled                   |
| "Invalid client" or similar        | Double-check the Client ID and Client Secret were copied correctly, with no extra spaces                                             |
| Lost your Client Secret            | Regenerate credentials in Fulfil, then update the Client ID and Secret in Purple Dot                                                 |
| Wrong workspace                    | Confirm the workspace subdomain from your Fulfil login URL (the part before `.fulfil.io`)                                            |

***

If you get stuck, contact Purple Dot support with your workspace and a description of where the setup failed.


# Point of Sale (Beta)

Purple Dot is developing the capability to transact pre-order sales via Shopify POS. This feature is currently in a Beta testing phase and will be made available to more merchants in due course.

Please contact <sales@getpurpledot.com> to learn more.

## How it works?

Purple Dot can allow in-store staff to transact pre-orders through our Point of Sale extension. It leverages our draft pre-order capability and allows the sales assistant to build a pre-order cart on behalf of the shopper.

The shopper is sent an email with a payment link to complete the transaction.

The fulfilment is managed in the same way as online pre-orders and will be shipped to the shopper once inventory arrives.

The sales staff and store location are captured as part of the transaction to allow appropriate commission calculations and reporting.

## Installation steps

1. Contact us to get started.
2. Purple Dot will install our "Pre-order POS" app into your store. This is an embedded app that can be launched from the Shopify POS app.
3. Add the app to a Smart Grid page to allow staff to use it in-store.

## Permission requirements from the merchant

Purple Dot will request the `read_users` permission to allow the Pre-order POS app to attribute sales to staff members.


# Integrate Purple Dot with Salesforce

Start by signing up to Purple Dot as a Merchant. If you don't have a Merchant Account yet, send us an email at <sales@getpurpledot.com> and we'll get you set up.

## Install the Purple Dot LINK cartridge

The Purple Dot LINK cartridge allows you to quickly integrate a Purple Dot instance into a Salesforce Commerce Cloud website. Download the Purple Dot cartridge and unzip its contents:

{% file src="/files/RrZKzm2xYuEV06VH0zKZ" %}
v22.1.0 Cartridge (SHA256 14825fc5698ecc1442f463ebf1cb5e666b085e038c43f30929050489d2bcfd9b)
{% endfile %}

The Purple Dot cartridge enables customers to make pre-orders for out-of-stock products on the merchant’s site. The Purple Dot cartridge provides next features on the SFCC platform:

* Custom pre order button and cart elements on the storefront
* Dedicated configuration page in Business Manager
* Jobs which export and upload shipping methods, inventory lists and product catalogs to Purple Dot service
* Refunds (full or partial)

The cartridge is designed for Salesforce Commerce Cloud API version 22.6 (Compatibility Mode: 21.7) with StoreFront Reference Architecture (SFRA) version 6.0.0. It also supports older SiteGenesis (SG) sites. The cartridge is designed for the US and GB locales, but can work with other locales.

**Glossary**

<table><thead><tr><th width="248">Term</th><th>Description</th></tr></thead><tbody><tr><td>SFCC</td><td>Salesforce Commerce Cloud</td></tr><tr><td>Business Manager (BM)</td><td>The primary tool used to configure the SFCC platform and customer storefront SFRA</td></tr><tr><td>SFRA</td><td>StoreFront Reference Architecture</td></tr><tr><td>SG</td><td>SiteGenesis</td></tr></tbody></table>

### Set Up Business Manager

#### Import Purple Dot cartridges

1. Download the cartridge source code.
2. Establish a new digital server connection with your SFCC Instance.
3. Import cartridges to a workspace in Salesforce UX Studio.

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F36FVxOkfEM7UNaSmAEbG%2Fimage.png?alt=media&amp;token=f80effb4-e025-4f9c-b11d-bf0fe80cc250" alt=""><figcaption></figcaption></figure>
4. Add cartridges to Project Reference of Server Connection.

   1. For **SFRA**, add the `int_purpledot` and `int_purpledot_sfra` cartridges.

      <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FF8kNPU1yiO51EXzP9A1P%2Fimage.png?alt=media&amp;token=7caddbff-4f42-457c-ba50-ae2ee56540ad" alt=""><figcaption></figcaption></figure>
   2. For **SG**, add the `int_purpledot`, `int_purpledot_controllers`, and `purpledot_sg_changes` cartridges.

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FqXCg758tfDuQsatZXJUq%2Fimage.png?alt=media&amp;token=819e5f42-b251-4676-8d12-fc105372d373" alt=""><figcaption></figcaption></figure>
5. Wait until Studio completes workspace build and uploads source codes to the sandbox.

#### Assign cartridges to the site

Go to `Administration > Sites > Manage Sites` and select your site from the list of “Storefront Sites”.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FZKqPnswYshTPdIGtLqFz%2Fimage.png?alt=media&amp;token=e74c0b23-72ce-4848-be2d-6c3b06d5da4b" alt=""><figcaption></figcaption></figure>

Go to the Settings tab for your site.&#x20;

For **SFRA sites**, in the beginning of the cartridge path add the following:

`int_purpledot:int_purpledot_sfra:`

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FT8h2uWGWxxslorfywh7d%2Fimage.png?alt=media&amp;token=a0cf1dfd-8411-43b1-a438-9ed4ddaca5f3" alt=""><figcaption></figcaption></figure>

**Note**: cartridge `storefront_base` is the core SFRA cartridge, which must be present as default SFRA cartridge to run SFRA sites.

For **SG sites**, in the beginning of the cartridge path add the following:

`purpledot_sg_changes:int_purpledot_controllers:int_purpledot:`

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FSwH5R3PBWwgrwpzBSpKK%2Fimage.png?alt=media&amp;token=ca9e4b13-f360-4517-8271-c3f1276033c8" alt=""><figcaption></figcaption></figure>

Note: cartridges `storefront_controllers` and `storefront_core` are the core Controllers cartridges, which must be present as default Controller cartridges to run SG sites.

#### Import metadata

Go to `Administration > Site Development > Site Import & Export`. Create a zip archive of the `metadata` folder and upload *metadata.zip*.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FKDwCRd87XLfjIcN104IX%2Fimage.png?alt=media&amp;token=ecdaa7e4-7651-4740-8e65-e747ad333a67" alt=""><figcaption></figcaption></figure>

Select *metadata.zip* and finish the import process.

### Configure Site

After import is successfully done, you should see the Purple Dot Custom Site Preference Group in the Business Manager by going to`Administration > Merchant Tools > Site Preferences > Custom Site Preferences`.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F7TXQOVK76EUiTH4aBStb%2Fimage.png?alt=media&amp;token=ded0eeb1-958d-4f66-8b7e-36a006c06860" alt=""><figcaption></figcaption></figure>

#### Set custom site preferences

From `Administration > Merchant Tools > Site Preferences > Custom Site Preferences`, select **Purple Dot**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FmcTwn8g1kcvA6iLo3e2E%2Fimage.png?alt=media&amp;token=c3a8d83f-1d2f-4c98-a5e4-7a12c128fc5f" alt=""><figcaption></figcaption></figure>

The following preference values need to be set:

<table><thead><tr><th width="241">Preference name</th><th>Description</th></tr></thead><tbody><tr><td>Enable PurpleDot</td><td>Enable/disable all Purple Dot instances across the site</td></tr><tr><td>API key</td><td>Value for Purple Dot SDK. Your API key can be retrieved from Purple Dot by going to Settings > Integration > API Keys.</td></tr><tr><td>Secret Key</td><td>Value for JSON Web Token generator. Your Shared Secret Key can be retrieved from Purple Dot by going to Settings > Integration > API Keys.</td></tr><tr><td>Button style</td><td>Custom CSS styles for the Purple Dot pre-order button element.</td></tr><tr><td>Cart style</td><td>Custom CSS styles for the Purple Dot cart button element.</td></tr></tbody></table>

### Set Up Jobs

There are three jobs that need to be set up:

* PurpleDotCatalogExport
* PurpleDotInventoryExport
* PurpleDotShippingMethodsExport

**Note:** Catalog export job supports only one catalog at a time by default. If there is a need to upload more than one catalog, duplicate existing catalog export job and change its job ID to match the following pattern - **PurpleDot\_CatalogExportJob\_**\<YOUR CUSTOM SUFFIX>.

The following steps are similar for all Purple Dot jobs. The specific steps for job marked with the name of this particular job:

1. Go to Administration > Administration > Operations > Job Schedules > \[PurpleDot\_CatalogExport/PurpleDot\_InventoryExport/PurpleDot\_ShippingMethodsExport].
2. Go to the Schedule and History tab in order to define job intervals. Your catalogs/inventory lists/shipping methods will be synced in the Purple Dot system each time jobs have been scheduled.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FRaQI2JquPRidWfC8v9e3%2Fimage.png?alt=media&amp;token=a52383df-3162-4bb9-bf10-1b515502c91b" alt=""><figcaption></figcaption></figure>

3. Go to the Job Step tab and click on the “Organization” button
4. Select needed site for every job step (**Note:** For the *CreateCatalogFeed* step in *PurpleDot\_CatalogExport job* the only applicable scope is “Organization”)

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FLFEhc6Qj6G5ZdEWepWxW%2Fimage.png?alt=media&amp;token=2bdaa22b-1a19-4b8a-bdc9-1d190b5720a9" alt=""><figcaption></figcaption></figure>

5. **\[*****PurpleDot\_ExportCatalog job*****]** Open CreateCatalogFeed step, enter catalog ID to export in the “CatalogID” field and click the “Assign” button. (**Note:** Only “owned” products from catalog will be exported, “assigned” products will be ignored)

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F0j81b4MMlx7AnQptPjSF%2Fimage.png?alt=media&amp;token=997a622c-f589-412a-97ac-fa059d1be6fd" alt=""><figcaption></figcaption></figure>

#### Provide Service Credentials

Go to `Administration > Operations > Services > Credentials`. Choose *purpledot.s3.aws.cred*.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FT2AcjPFAiMqSpq7Ac1o1%2Fimage.png?alt=media&amp;token=621fa66a-4043-4a65-bac3-a1556e0c439e" alt=""><figcaption></figcaption></figure>

Enter service credentials provided by Purple Dot, setting the provided AWS access key as user and access secret as password.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FovG9VaSe1qzaCnMHCN1X%2Fimage.png?alt=media&amp;token=7ccaeb6b-4c53-4e79-9e0e-3355e728d9c9" alt=""><figcaption></figcaption></figure>

Test that the jobs work by clicking Run Now.

**Warning:** If the jobs fails immediately or if the storefront isn't being updated, you might need to reactivate your current code version.

### OCAPI settings

**Warning:** OCAPI permissions need to be appended in addition to any pre-existing permissions.

Enter OCAPI permissions within Business Manager: `Administration > Site Development > Open Commerce API Settings`. See this “*purpledot ocapi shop.json*” file for required permissions.

{% file src="/files/o6eKoVRBsCSE9YcvHld7" %}

{% file src="/files/xGODq3neMzWOkPHWZwi4" %}

The cartridge registers one hook-point to facilitate further customization:

* The hook-point *dw\.ocapi.shop.order.afterPATCH* is used to update payment status of the order placed with PurpleDot pre-order checkout

### Add Salesforce Commerce Cloud credentials to Purple Dot

In your Purple Dot Merchant Portal, go to Settings > Integration > Connected SFCC Store and click Connect. Fill in the SFCC instance and site you are connecting to, the OCAPI Client ID and password, if using a sandbox instance the Sandbox username and password, and click save. Credentials will be validated upon saving.

&#x20;![](https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FhfcmzIjGwBZ1qjnt6kxF%2FScreenshot%202024-08-07%20at%2016.32.59.png?alt=media\&token=445a6842-64fa-463a-b026-5e348c8a7983)

## Integrate Purple Dot with your SFRA site

### Edit models

**Note: all changes are already made in the int\_catch\_sfra cartridge.** **Files in the current cartridge use scripts and utilities from core cartridges. The file paths inside require() functions were changed to keep the relative paths to the core cartridges.**

For each of the following files, add the required code:

1. **app\_storefront\_base/cartridge/templates/default/purpleDot/cartbutton.isml**\
   If using the express checkout and a separate card, set `enableCart` to `false`:\
   `window.PurpleDot.init({ apiKey: '...', enableCart: false });`
2. **app\_storefront\_base/cartridge/models/product/decorators/index.js**

   Add the following row to the exported object in line 31 to extend product model decorators:

   ```jsx
   pdProduct: require('*/cartridge/models/product/decorators/pdProduct')
   ```
3. **app\_storefront\_base/cartridge/templates/default/common/htmlHead.isml**

   Add the following rows to line 32 to inject the Purple Dot SDK script and custom cartridge css styles to the page:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <link rel="stylesheet" href="${URLUtils.staticURL('/css/purpledot.css')}" />
   <isinclude template="purpleDot/sdkScript" />

   <iscomment>Purple Dot code</iscomment>
   ```
4. **app\_storefront\_base/cartridge/templates/default/components/header/headermenu.isml**

   Put the following rows to the line 33 to add link to Purple Dot self-service widget to the header menu:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <isif condition="${require('*/cartridge/scripts/purpleDot/helpers/pdHelper').getPreference('enable')}">

   	<li class="nav-item" role="presentation">
   		<a href="${URLUtils.https('PurpleDot-StatusPage')}" id="pd-history" class="nav-link" role="link" tabindex="0" target="_blank">${Resource.msg('link.name.preorderhistory', 'purpledot', null)}</a>
   	</li>

   </isif>

   <iscomment>Purple Dot code</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FpcqQaiDZXMwZcOYSE35S%2Fimage.png?alt=media&amp;token=5dfc0165-4965-42b9-90c0-718af3750c98" alt=""><figcaption></figcaption></figure>
5. **app\_storefront\_base/cartridge/templates/default/components/header/pageHeader.isml**

   Add the following rows at line 45 to add the Purple Dot “Cart button” element to the page header:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <iscomment>Purple Dot Cart Button</iscomment>
   <isinclude template="purpleDot/cartbutton" />

   <iscomment>PurpleDot code</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FHCoysRODpACoHkTafyIu%2Fimage.png?alt=media&amp;token=08959193-bef2-4c31-bf39-7ef27be07807" alt=""><figcaption></figcaption></figure>
6. **app\_storefront\_base/cartridge/templates/default/product/components/addToCartGlobal.isml**

   Wrap the button and input elements responsible for the native `addAllToCart` button on the PDPs with product sets and product bundles with following rows in line 3 to insert the Purple Dot Pre-order button on the page:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <isif condition="${product.pdProduct.isEnabled}">

   	<isset name="isInStock" value="${product.pdProduct.isInStock}" scope="page" />
   	<isset name="isAvailableForPreorder" value="${product.pdProduct.productToRender.availableForPreorder}" scope="page" />
   	<isset name="productIsSoldOut"
   		value="${!product.pdProduct.isInStock && !isAvailableForPreorder}"
   		scope="page" />
   	<isset name="productIsReadyToPreorder"
   		value="${!isInStock && isAvailableForPreorder}"
   		scope="page" />
   	<isset name="isMasterProductSelected" value="${product.pdProduct.masterProductID.trim() === product.id.trim()}" scope="page" />
   	<isset name="isSimpleProduct" value="${product.productType ==='standard'}" scope="page" />
   	
   	<input type="hidden" class="add-to-cart-url" value="${pdict.addToCartUrl}">
   	<button class="add-to-cart btn btn-primary ${(isMasterProductSelected && !isSimpleProduct) || productIsReadyToPreorder ? "d-none" : ""}"
   		data-toggle="modal" data-target="#chooseBonusProductModal"
   		data-pid="${product.id}"
   		${!product.readyToOrder || !product.available || productIsSoldOut ? "disabled" : ""}
   		aria-disabled="${productIsSoldOut}">
   		
   		<i class="fa fa-shopping-bag"></i>
   		<span>${productIsSoldOut ?  Resource.msg('button.title.soldout', 'purpledot', null) : Resource.msg('button.addtocart', 'common', null)}</span>
   	</button>

   	<iscomment>Purple Dot Preorder Button</iscomment>
   	<isinclude template="purpleDot/preorderbutton" />

   <iselse/>

   	... // template content goes here

   </isif>

   <iscomment>Purple Dot code</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FXXE8Yp4Xt9r0SJAM0McE%2Fimage.png?alt=media&amp;token=cde7fe55-bda8-469e-a837-1fe8d4956c0f" alt=""><figcaption></figcaption></figure>
7. **app\_storefront\_base/cartridge/templates/default/product/components/addToCartGlobal.isml**

   Wrap the button and input elements responsible for the native `addToCart` button on the PDP with following rows in line 3 to insert the Purple Dot Pre-order button on the page:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <isif condition="${product.pdProduct.isEnabled}">

   	<isset name="isInStock" value="${product.pdProduct.isInStock}" scope="page" />
   	<isset name="isAvailableForPreorder" value="${product.pdProduct.productToRender.availableForPreorder}" scope="page" />
   	<isset name="productIsSoldOut"
   		value="${!product.pdProduct.isInStock && !isAvailableForPreorder}"
   		scope="page" />
   	<isset name="productIsReadyToPreorder"
   		value="${!isInStock && isAvailableForPreorder}"
   		scope="page" />
   	<isset name="isMasterProductSelected" value="${product.pdProduct.masterProductID.trim() === product.id.trim()}" scope="page" />

   	<input type="hidden" class="add-to-cart-url" value="${pdict.addToCartUrl}">

   	<button class="add-to-cart-global btn btn-primary ${isMasterProductSelected || productIsReadyToPreorder ? "d-none" : ""}"
   		data-pid="${product.id}"
   		${!product.readyToOrder || !product.available || productIsSoldOut  ? "disabled" : ""}
   		aria-disabled="${!productIsSoldOut}">

   		<i class="fa fa-shopping-bag"></i>
   		
   		<isif condition="${product.productType === 'set' || product.productType === 'bundle'}">
   		
   			<span>
   				${productIsSoldOut ? Resource.msg('button.addalltocart', 'common', null) : Resource.msg('button.title.soldout', 'purpledot', null)}
   			</span>
   			
   		<iselse>
   		
   			<span>
   				${productIsSoldOut ? Resource.msg('button.addtocart', 'common', null) : Resource.msg('button.title.soldout', 'purpledot', null)}
   			</span>

   		</isif>

   	</button>

   	<iscomment>Purple Dot Preorder Button</iscomment>
   	<isinclude template="purpleDot/preorderbutton" />

   <iselse/>

   	... // template content goes here

   </isif>

   <iscomment>Purple Dot code</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FhVJRmj5EmVSb3nN7Ddql%2Fimage.png?alt=media&amp;token=b0527d9a-f6ca-4826-973c-4712a3e024ee" alt=""><figcaption></figcaption></figure>
8. **app\_storefront\_base/cartridge/templates/default/product/productTile.isml**

   Put the following rows to the line 21 to include pre-order label to the product tile:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <isinclude template="purpleDot/preorderlabel" />

   <iscomment>Purple Dot code</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FodnpvrIxRazRhKdjOcqC%2Fimage.png?alt=media&amp;token=5a347b49-40af-4dc3-8d43-83b9674fc9cd" alt=""><figcaption></figcaption></figure>
9. **app\_storefront\_base/cartridge/templates/default/product/components/quantity.isml**

   Wrap the template elements responsible for the quantity number selection on the PDP with following rows in line to hide the quantity selector when the Purple Dot cartridge is enabled and Pre-order button is shown on the page:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <isif condition="${product.pdProduct.isEnabled}">

   	<isset name="isInStock" value="${product.pdProduct.isInStock}" scope="page" />
   	<isset name="isAvailableForPreorder" value="${product.pdProduct.productToRender.availableForPreorder}" scope="page" />

   	<label for="quantity-${loopState && loopState.count ? loopState.count : '1' }" class="${!isInStock && isAvailableForPreorder ? "d-none" : ""}">
   		${Resource.msg('label.quantity', 'common', null)}
   	</label>

   	<select class="quantity-select custom-select form-control ${!isInStock && isAvailableForPreorder ? "d-none" : ""}" id="quantity-${loopState && loopState.count ? loopState.count : '1' }">

   	<isloop items="${product.quantities}" var="quantity">
   		<option value="${quantity.value}"
   			<isif condition="${product.productType !== 'bundle'}">data-url="${quantity.url}"</isif>
   			${quantity.selected ? 'selected' : ''}
   		>
   			${quantity.value}
   		</option>
   	</isloop>

   	</select>

   <iselse/>

   	... // template content goes here

   </isif>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FjM5WpZv4MjP8XHhHk5Wc%2Fimage.png?alt=media&amp;token=b5d6458d-ee5a-49f3-a1bb-6a3a28f0fd68" alt=""><figcaption></figcaption></figure>

### Edit client-side scripts

1. **app\_storefront\_base/cartridge/client/default/js/product/detail.js**

   Put the following row to the line 3 to add import helper function to the client-side script:

   ```jsx
   // Purple Dot code
   var pdHelper = require('../purpleDot/helpers/pdHelper');
   // Purple Dot code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FufQwPN3lK6PWU8nkjaZx%2Fimage.png?alt=media&amp;token=4eff2929-c5fc-4897-8d0e-27db12eca377" alt=""><figcaption></figcaption></figure>

   Wrap native code responsible for update of the addToCart button in the updateAddToCart() function in the line 76 to replace change handling behavior of the addToCart button when cartridge is enabled:

   ```jsx
   // Purple Dot code
   if (response.product.pdProduct.isEnabled) {
   	pdHelper.handleAddToCartButton(response);
   } else {
   	... // client-side script content goes here
   }
   // Purple Dot code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FSnn8JzXW7dN3OQZeZSZy%2Fimage.png?alt=media&amp;token=e450352d-cbcf-4c07-aec9-05619c609b57" alt=""><figcaption></figcaption></figure>
2. **app\_storefront\_base/cartridge/client/default/js/product/detail.js**

   ```jsx
   // Purple Dot code
   var pdHelper = require('../purpleDot/helpers/pdHelper');
   // Purple Dot code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2Fkkwnk1e5z40mxIJGypBh%2Fimage.png?alt=media&amp;token=7c796f85-7358-4425-858e-bcf5b3b0134c" alt=""><figcaption></figcaption></figure>

   Add the following row to the line 80 in the `fillModalElement()` function to add custom function responsible for Purple Dot load script initialization on `quickView` modal window open:

   ```jsx
   // Purple Dot code
   pdHelper.initializePurpleDotLoadScript(data);
   // Purple Dot code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FSnWGDI9HciLlrOq1jUdo%2Fimage.png?alt=media&amp;token=43895830-4fa8-461b-beb3-6f352b5f29b7" alt=""><figcaption></figcaption></figure>

   Add the following row to the line 153 in the `updateAddToCart()` function to handle `addToCart` button in the `quickView` modal window when cartridge is enabled:

   ```jsx
   // Purple Dot code
   if (response.product.pdProduct.isEnabled) {
   	pdHelper.handleAddToCartButton(response);
   } else {
   	// ... client-script content goes here
   }
   // Purple Dot code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F8FFuHq8bCbQyAFwMmoxh%2Fimage.png?alt=media&amp;token=3e6e52b7-d452-4000-aa0d-4281306a359c" alt=""><figcaption></figcaption></figure>

## Integrate Purple Dot with your SG site

### Edit controllers

**Note:** **all changes are already made in the purpledot\_sg\_changes cartridge. Files in the current cartridge use scripts and utilities from core cartridges. The file paths inside require() and importScript() functions were changed to keep the relative paths to the core cartridges .**

1. app\_storefront \_controllers/cartridge/models/controllers/Product.js

   Put the following rows to the show()function in line31 to check if product is configured and available for pre-order via PurpleDot service:

   ```jsx
   // PurpleDot code start
   var productToRender = require('*/cartridge/scripts/purpleDot/helpers/pdHelper').getProductToRender(product);
   // PurpleDot code end
   ```

   Put the following row in line 39 to send value from the productToRender variable to the template’s pipeline dictionary:

   ```jsx
   productToRender: productToRender, // PurpleDot code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FwL3FLUJoFMdog84iCR1T%2Fimage.png?alt=media&amp;token=5ecedd11-78c9-4a93-b9d6-5782e766c873" alt=""><figcaption></figcaption></figure>

   Put the following rows to the variation() function in line 220 to check if product’s variant is configured and available for preorder via PurpleDot service:

   ```jsx
   // PurpleDot code start
   var productToRender = require('*/cartridge/scripts/purpleDot/helpers/pdHelper').getProductToRender(product);
   // PurpleDot code end
   ```

   Extend object in getView() function with the following row in lines 238, 245, 253 to send value from the productToRender variable to the template’s pipeline dictionary:

   ```jsx
   productToRender: productToRender, // PurpleDot code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FtAQtf54qaxiKdqVWj1Qn%2Fimage.png?alt=media&amp;token=e2a38a99-0580-4374-b63d-bc1943990136" alt=""><figcaption></figcaption></figure>

### Edit templates

1. **app\_storefront \_core/cartridge/templates/default/components/header/header.isml**

   Add the following rows to line 51 at the bottom of file to add the Purple Dot “Cart button” element to the page header:

   ```html
   <iscomment>Purple Dot Cart Button</iscomment>
   <isinclude template="purpleDot/cartbutton" />
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FPL30npMfgYaKITIxdOUl%2Fimage.png?alt=media&amp;token=9bedeaa9-fe35-447e-9a52-cd1550cbbe52" alt=""><figcaption></figcaption></figure>
2. **app\_storefront \_core/cartridge/templates/default/components/header/header.isml**

   Add the following rows to the line 45 at the bottom of file to add a link to Purple Dot’s self-service widget to the header menu:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <isif condition="${require('*/cartridge/scripts/purpleDot/helpers/pdHelper').getPreference('enable')}">

   	<iscomment>Purple Dot self-service widget</iscomment>
   	<li>
   		<a href="${URLUtils.https('PurpleDot-StatusPage')}" title="Preorder History" target="_blank">
   			<span>${Resource.msg('link.name.preorderhistory', 'purpledot', null)}</span>
   		</a>
   	</li>

   </isif>

   <iscomment>Purple Dot code</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FKwVbGFy4hbEti97EmtG7%2Fimage.png?alt=media&amp;token=fcadef9b-c500-4d10-a7a7-6f0478f93275" alt=""><figcaption></figcaption></figure>
3. **app\_storefront \_core/cartridge/templates/default/components/header/htmlhead.isml**

   Add the following rows at the line 30 to include Purple Dot SDK script in the page header:

   ```html
   <iscomment> Load the Purple Dot SDK </iscomment>
   <isinclude template="purpleDot/sdkScript"/>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FJcHpwHaUKXsvesQjmcnq%2Fimage.png?alt=media&amp;token=04b49dc4-c4bb-47bd-96d5-948363c4bdd1" alt=""><figcaption></figcaption></figure>

   Add the following rows to the line 85 to add cartridge styles to the page header:

   ```html
   <!-- Purple Dot Styles -->
   <link rel="stylesheet" href="${URLUtils.staticURL('/css/purpleDot.css')}" />
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FUmLCgkPcSO1LEh5q8h1I%2Fimage.png?alt=media&amp;token=8e26c54a-0dea-4c37-b8f5-c3e9391a805f" alt=""><figcaption></figcaption></figure>
4. **app\_storefront \_core/cartridge/templates/default/product/productcontent.isml**

   Add the following row to line 3 to add import helper function to the client-side script:

   ```html
   <iscomment>Purple Dot</iscomment>

   <isif condition="${pdict.Product.getAvailabilityModel().isInStock()}">

   	// ...template content goes here

   </isif>

   <iscomment>Purple Dot</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FfF72YFpdkIhcHUD5dagq%2Fimage.png?alt=media&amp;token=f8d3bbe3-0a43-48f3-a1b6-0b013bbf6302" alt=""><figcaption></figcaption></figure>

   Wrap the block of the template responsible for “Add to cart” button with the following rows in line 226 to add the Purple Dot “Pre-order” button element on the PDP page:

   ```html
   <iscomment>Purple Dot</iscomment>

   <isif condition="${pdict.Product.getAvailabilityModel().isInStock()}">

   	// ...contents of the template go here

   <iselseif condition="${pdict.productToRender.availableForPreorder}"/>

   	<iscomment>PurpleDot Preorder Button</iscomment>
   	<isinclude template="purpleDot/preorderbutton" />

   <iselse/>

   	<button id="add-to-cart" type="button" title="${Resource.msg('button.title.soldout', 'purpledot', null)}" value="${Resource.msg('button.title.soldout', 'purpledot', null)}" class="button-fancy-large add-to-cart-disabled" disabled="disabled">${Resource.msg('button.title.soldout', 'purpledot', null)}</button>

   </isif>

   <iscomment>Purple Dot</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FT13w9iZvmsGxWHseIUm6%2Fimage.png?alt=media&amp;token=7c69ef4d-0b95-4610-80b4-ce29ce0db7c0" alt=""><figcaption></figcaption></figure>
5. **app\_storefront\_core/cartridge/templates/default/product/producttile.isml**

   Add the following rows to the line 129 to add the “preorder label” element to the product tile component:

   ```html
   <iscomment>PurpleDot Pre-order label</iscomment>

   <isset name="pdProduct" value="${pdict.Product}" scope="page" />
   <isinclude template="purpleDot/preorderlabel" />
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2Fz2Ln5ekqcUdz46Mv5kdt%2Fimage.png?alt=media&amp;token=3b224214-8ac2-4ead-9ceb-3d01f1f4f0ee" alt=""><figcaption></figcaption></figure>
6. **app\_storefront\_core/cartridge/templates/default/product/producttopcontentPS.isml**

   Wrap the form with the following rows in line 153 in the end of the file to add the Purple Dot “Pre-order” button element on the “bundle” product page:

   ```html
   <isif condition="${pdict.Product.getAvailabilityModel().isInStock()}">

   	// contents of the core cartridge go here

   <iselseif condition="${pdict.productToRender.availableForPreorder}"/>

   	<iscomment>Purple Dot Preorder Button</iscomment>
   	<isinclude template="purpleDot/preorderbutton" />

   <iselse/>

   	<button id="add-to-cart" type="button" title="${Resource.msg('button.title.soldout', 'purpledot', null)}" value="${Resource.msg('button.title.soldout', 'purpledot', null)}" class="button-fancy-large add-to-cart-disabled pd-sold-out" disabled="disabled">${Resource.msg('button.title.soldout', 'purpledot', null)}</button>

   </isif>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F0ZOgqgPFKUrNJ1IermEF%2Fimage.png?alt=media&amp;token=c122d7e7-98be-45b1-bb99-d3506388946d" alt=""><figcaption></figcaption></figure>
7. **app\_storefront\_core/cartridge/templates/default/product/components/productsetproduct.isml**

   Wrap the form with the following rows in line 73 in the end of the file to add the Purple Dot “Pre-order” button element on the “bundle” product page:

   ```html
   <iscomment>Purple Dot code</iscomment>

   <isif condition="${pdict.Product.getAvailabilityModel().isInStock()}">

   	// ...form content

   <iselseif condition="${pdict.productToRender.availableForPreorder}"/>

   	<isinclude template="purpleDot/preorderbutton"/>

   <iselse />

   	<button id="add-to-cart" type="button" title="${Resource.msg('button.title.soldout', 'purpledot', null)}" value="${Resource.msg('button.title.soldout', 'purpledot', null)}" class="button-fancy-large add-to-cart-disabled" disabled="disabled">${Resource.msg('button.title.soldout', 'purpledot', null)}</button>

   </isif>

   <iscomment>Purple Dot code</iscomment>
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FDKjsRTvU7nGKHHzpfhvU%2Fimage.png?alt=media&amp;token=0ef0d382-ad07-45e4-a331-29502d9ea86e" alt=""><figcaption></figcaption></figure>
8. **app\_storefront\_core/cartridge/templates/default/product/components/recommendations.isml**

   Add the following rows in line 47 to add the “pre-order label” element to the product tiles in the blocks with recommendations:

   ```html
   <iscomment>PurpleDot Pre-order label</iscomment>
   <isset name="pdProduct" value="${pdict.Product}" scope="page" />
   <isinclude template="purpleDot/preorderlabel" />
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FkcGTcnoBJoMHD5Flxu1p%2Fimage.png?alt=media&amp;token=42ddc5a9-18ee-4caa-85ae-7abd2e20b9a9" alt=""><figcaption></figcaption></figure>

### Edit client-side scripts

1. **app\_storefront\_core/cartridge/js/pages/products/productSet.js**

   Put the following rows to the line 7 in the top of file to add the handleSoldoutButtonState() function responsible for keeping the “Sold out” button element disabled after page loads:

   ```jsx
   // PurpleDot code
   function handleSoldoutButtonState() {
   	var pdSoldoutButton = $('button.pd-sold-out');
   	
   	if (pdSoldoutButton.length > 0) {
   		pdSoldoutButton.prop('disabled', true);
   	}
   }
   // PurpleDot code
   ```

   Put the following rows to the line 32 in the top of file to the updateAddToCartButtons() function to keep “Sold out” button element disabled after page loads for ‘bundle’ products:

   ```jsx
   // PurpleDot Code
   handleSoldoutButtonState();
   // PurpleDot Code
   ```

   <figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FlD53lRw9ap7Y6n94Vumi%2Fimage.png?alt=media&amp;token=cdc8463f-e99f-4644-abf2-81609c85b289" alt=""><figcaption></figcaption></figure>

### Additional client-side APIs

Here are some additional client side APIs that can be used to customise the storefront experience

#### numberOfPreorderItemsInBag

You can use the following code in your storefront to determine the number of preorder items that a shopper has added to their cart.

```javascript
window.PurpleDot.numberOfPreorderItemsInBag().then(
    (preorderItemsInBag) => {
        // ...
    }
);
```

#### openCheckout

You can open the Purple Dot checkout using the following code

```javascript
window.PurpleDot.openCheckout()
```

### Events

The Purple Dot client-side SDK emits the following events on the storefront.

| Event name          | Description                                                      |
| ------------------- | ---------------------------------------------------------------- |
| PurpleDot:Ready     | Emitted when the Purple Dot SDK is initialised and ready for use |
| PurpleDot:AddToCart | Emitted when the shopper has added a preorder item to their cart |

### Building a custom preorder checkout button

The above APIs and events can be leveraged to build a custom preorder checkout button. The following is a simplified example:

{% code overflow="wrap" lineNumbers="true" %}

```html
<body>
    <button id="preorder-checkout-button">Checkout</button>
    
    <script>
        const preorderCheckoutButton = document.querySelector(
            '#preorder-checkout-button'
        );
        
        preorderCheckoutButton.style.visibility = 'hidden';
        
        async function changeCheckoutButtonVisibility() {
            const numberOfPreorderItemsInBag = await window
                .PurpleDot
                .numberOfPreorderItemsInBag();
                
            preorderCheckoutButton.style.visibility = numberOfPreorderItemsInBag > 0
                ? 'initial'
                : 'hidden';
        }
        
        const eventsToListen = ['PurpleDot:Ready', 'PurpleDot:AddToCart'];
        
        for (const event of eventsToListen) {
            window.addEventListener(event, () => {
                changeCheckoutButtonVisibility();
            });
        }
        
        preorderCheckoutButton.addEventListener('click', (event) => {
            event.preventDefault();
            window.PurpleDot.openCheckout();
        });
    </script>
</body>
```

{% endcode %}

## Test the Integration

Follow the steps below to validate that you have successfully installed the Purple Dot cartridge.

### Business Manager \[Inventory Management]

All cartridge components are located in "Merchant Tools > Site Preferences > Custom Site Preference > PurpleDot".

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FScxm7WWYaBiHHW9v82JI%2Fimage.png?alt=media&amp;token=99673cf1-4b30-4c02-9d2a-e383734954ca" alt=""><figcaption></figcaption></figure>

PurpleDot service needs to be enabled. Specify your *PurpleDot Public Key* and *PurpleDot API Key*.

#### **Configure product**

1. Go to Merchant Tools > Products and Catalogs >Inventory.
2. Choose an inventory book assigned to the current site.
3. Go to the “Records” tab, find the product that should be configured and click the “Edit” button.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FCOQkbDAZetzKy1V9Xhp7%2Fimage.png?alt=media&amp;token=50a9eb1d-e4f0-468d-9fb3-0efdfcb639c9" alt=""><figcaption></figcaption></figure>

4. Configure the product’s availability settings by setting “Allocation” field value to 0.0 (zero).
5. Set the “None” checkbox in for the “Pre-Order/Backorder Handling” field.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FX3W9CfGfFoFGmEmSgsqx%2Fimage.png?alt=media&amp;token=486030cf-5c3a-4eb8-894b-f3b619ebcef2" alt=""><figcaption></figcaption></figure>

Product Availability Status should change to **Not Available.**

#### **Synchronize catalog and shipping methods with Purple Dot platform**

1. Go to Administration > Operations > Jobs > \[\[PurpleDot\_Job]]

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FPcXGnPbhWF2JJPDCt5AG%2Fimage.png?alt=media&amp;token=ce772c6a-3921-4c3c-a762-77c94f077555" alt=""><figcaption></figcaption></figure>

2. Run each job by clicking the “Run now” button

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FPdFpgWI9mg9PHlBWtDPH%2Fimage.png?alt=media&amp;token=032bd7c6-ceb9-430f-964e-b0e750e12cca" alt=""><figcaption></figcaption></figure>

#### **Create waitlist in the Purple Dot dashboard**

3. Create a waitlist in the PurpleDot dashboard \[Putting a Product on Pre-order]

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FXzwhkJ22043tkoA0hyyw%2Fimage.png?alt=media&amp;token=d99a8ba3-9983-420f-a800-8895cd0596f5" alt=""><figcaption></figcaption></figure>

4. Add configured product to the waitlist \[From your Catalogue]

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FTw2QU0uokMv0paoWQoyN%2Fimage.png?alt=media&amp;token=a43d68f2-a9d7-4a14-b159-de5bb6a900e8" alt=""><figcaption></figcaption></figure>

5. Configure and save a waitlist.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FGOLqHu01Q0deQESjiHqJ%2Fimage.png?alt=media&amp;token=4d08d6c4-ced9-4c71-9c2a-5f9095904bde" alt=""><figcaption></figcaption></figure>

### Storefront \[Visual Components – PDP, Checkout and Self Service]

#### PDP

On the PDP page with the configured product the custom “Pre-order” button should appear.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FexYMYroPn2jneENC9Hza%2Fimage.png?alt=media&amp;token=5d61a5a8-98a9-45b0-b0db-12fae3904fed" alt=""><figcaption></figcaption></figure>

After adding the configured product to the pre-order list, the custom Purple Dot cart icon should appear near the default storefront cart icon.

In the BM inventory data should change:

* Pre-Order/Backorder Allocation: *your data*.
* Availability Status: **Pre-order**.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F6ozhl2dJlpqoctCQUMGs%2Fimage.png?alt=media&amp;token=4708f1a5-5154-468f-bb2e-0fd7a718c500" alt=""><figcaption></figcaption></figure>

Proceed to checkout by clicking the “Checkout” button.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FmOuBli9V7jxKJA51vuPf%2Fimage.png?alt=media&amp;token=31442ccc-8665-48a7-9ee5-fa31850b910b" alt=""><figcaption></figcaption></figure>

The modal window with Purple Dot pre-order checkout should appear.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2F9x1cnegm7bjZ75Zyjzf9%2Fimage.png?alt=media&amp;token=877f6db6-99b9-418b-8ed3-f41a4246910f" alt=""><figcaption></figcaption></figure>

#### **Pre-order label**

On the product tile of the configured product the “Pre-order” label should appear.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FJljn6G1VsE9WMTGwmDww%2Fimage.png?alt=media&amp;token=631eb243-c149-4b0e-a0d8-becfaa384c4f" alt=""><figcaption></figcaption></figure>

#### **Self-service widget**

Click the “Pre-order history” link.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FKxnixpMs9Ic5iGq4Wb0n%2Fimage.png?alt=media&amp;token=c6e4b791-79e1-426d-a6ca-305310d512df" alt=""><figcaption></figcaption></figure>

A new page with PurpleDot self-service widget should open.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FA7PaU75nZ2Mf6KPdfEGl%2Fimage.png?alt=media&amp;token=f887eff7-42e8-4af9-a7a0-c7b37adf3bb5" alt=""><figcaption></figcaption></figure>

### Other \[Refund, Taxes and SSO]

#### **Refunds**

Place an order using Purple Dot pre-order checkout. Go to the Purple Dot dashboard and find your pre-order in the “Pre-orders” tab. Click on the pre-order.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FnnknYWT2D2CwujEyjXnr%2Fimage.png?alt=media&amp;token=cf3c25ee-5879-4345-a636-cc5a20c86d1c" alt=""><figcaption></figcaption></figure>

Export your pre-order to the SFCC by clicking the “Export pre-order to SFCC button”.

Click the “Refund payment” button.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FhLfPSmjvb6r11wPtARKC%2Fimage.png?alt=media&amp;token=fff7aa81-1f76-4793-abb0-923f45fb327a" alt=""><figcaption></figcaption></figure>

Enter the refund amount and click the “Confirm refund” button.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FXZPPW9uPJeYZor1iVH6R%2Fimage.png?alt=media&amp;token=5d0dd730-3e4b-4830-9154-41ae0f058f3d" alt=""><figcaption></figcaption></figure>

Go to the BM: `Merchant Tools > Ordering > Orders` and find order.

<figure><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FqkMwIpBm5GCNpJJ0Ec1b%2Fimage.png?alt=media&amp;token=ff52534d-41c0-4fdf-9d58-1b241e6a52fa" alt=""><figcaption></figcaption></figure>

Check order notes. A note with the refund amount in the order’s “Notes” tab should appear in order notes.

#### **Login**

Login to the Purple Dot dashboard is via an email magic link of SSO. See separate documentation for SSO configuration.

#### **Gift Cards**

If required, ask the Purple Dot team to enable the Clutch Gift Cards integration.

## Download Documentation

Download the full Purple Dot cartridge documentation:

{% file src="/files/zVoyU0TmkV5m8PoDSFFX" %}
v22.1.0 Docs
{% endfile %}


# Upgrading to 2024-08-29

We are improving our exports process for SFCC, this will require SLAS credentials for our integration and a cartridge update.

You can create the required client credentials for us by following the [SFCC documentation here](https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas.html). Specifically we need a private client which has sufficient scopes to use the [createOrders](https://developer.salesforce.com/docs/commerce/commerce-api/references/orders?meta=createOrders) API. This should be just be `sfcc.ts_ext_on_behalf_of` and `sfcc.orders.rw`.

Once the client has been created you can add the new credentials in the Purple Dot integration settings page.

To fully benefit from this upgrade you will also need to upgrade your client to install some additional hooks which will ensure that the shoppers email address is set correctly on the order and also automatically set the confirmed flag and export status.

We will share both an updated copy of the cartridge code and also a Git repository so you can easily identify the changes between versions.

### Changes

* SLAS client credentials are now required to export orders from Purple Dot to SFCC
  * This makes exporting easier and more reliable by decoupling it from the Basket in SFCC which means you can export orders even if the waitlist is closed, and will improve the accuracy of prices on the exported order.
* Order attributes
  * purpleDot\_isRefunded has been removed, it was never set.
* Product Line Item attributes
  * purpleDot\_waitlistId has been added.
  * purpleDot\_shipDates has been removed.
* Orders will be automatically created with the following attributes
  * purpleDot\_isPreOrdered: true
  * Confirmation Status: Confirmed
  * Export Status: Ready to Export
* Preorder line items will automatically have:
  * purpleDot\_waitlistId: {The ID of the waitlist the item was assigned to in Purple Dot}
  * purpleDot\_lineItemId: {The ID of the line item in Purple Dot}
* The default checkout mode is now express instead of separate bag.

### Upgrade process

To upgrade to the new release you will need to follow this process

* [Create a private SLAS client](https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas.html) with the scopes `sfcc.ts_ext_on_behalf_of` and `sfcc.orders.rw` for Purple Dot and save the client id and secret in your Purple Dot integration settings page.
* Upgrade the cartridge to the latest release. If you have modified the cartridge you can follow the diff in git to apply the required changes.
* In System Object Attribute settings find Product Line Items and remove the `purpleDot_shipDates` attribute. It was never used.
* In System Object Attribute settings find Orders and remove the `purpleDot_isRefunded` attribute. It was never used.


# Integrate into another platform

*While Purple Dot natively integrates with Shopify and Salesforce, it can be easily adapted to integrate with other e-commerce platforms by using our APIs and SDKs directly.*

## Platform integration overview

Purple Dot integrates with your existing storefront and enables you to create pre-order experiences.

### Choose a Checkout Flow

Purple Dot supports a number of different checkout flows:

* **Express:** This checkout method presents a quick checkout modal to the shopper that opens directly when the Add to Cart button is clicked, so that the shopper can pre-order one or more of that item right away without any other products.
* **Separate Bag:** This checkout method is much like Express but adds a pre-order specific cart for the shopper to use to purchase multiple different pre-order items in one go. This comes with an additional pre-order cart component you can integrate into your store. This is a great option for situations in which a Shopper might want to pre-order multiple variants of the same product or products that go well together.
* **Combined:** This checkout method allows the shopper to add a pre-order item to their cart, but also continue shopping for other in-stock and pre-order items. When they are ready to checkout, they can be presented with a checkout that allows them to combine both pre-order and in-stock items at once, and choose to either ship them together or separately. *This method is not publicly available on non-Shopify stores please contact Purple Dot support if you need this option.*

{% hint style="info" %}
If you are unsure which checkout flow your store is configured for, please reach out to Purple Dot Support to confirm, or to switch from one checkout method to another.
{% endhint %}

The integration requirements will differ slightly depending on which checkout method is chosen.

## Express & separate bag

### Overview

There are 3 key requirements an integration needs to implement for an Express checkout:

* **Displaying pre-order items.** Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The integration needs to show that those items are on pre-order, with the estimated ship dates, the "Learn more” informational content and a “Pre-order” call to action.
* **Using the Express pre-order checkout.** When pre-ordering an item, instead of adding the item to the cart, the integration needs to launch our Express checkout modal and provide the variant ID, release ID, currency, and quantity.
* **Embedding the Shopper portal.** The shopper self-service portal lets shoppers manage their pre-orders. The integration needs to be embedded on a page in the storefront that the shoppers will be directed to in their confirmation email.

### Displaying pre-order items

Purple Dot is the source of data for which items are on pre-order and their estimated ship dates. The [Pre-order availability API](#purple-dot-browser-availability) can be queried for the pre-order status of any product or variant on the store.

Anywhere a product can be added to cart (on product pages, or collection pages and elsewhere with add to cart controls) we need to decide whether the product is in stock, sold out or on pre-order. To help with this we provide an extensible product availability API which you can use to check the state of the item.

#### **Pre-order pages**

On pre-order pages you should check the *active variant* against the availability API. If it is on pre-order you must show the Pre-order CTA, required estimated shipping dates, and Purple Dot branding to the shopper.

#### Collection pages

On collection pages and in any situation in which you display a "product" rather than individual variants you may wish to display a specific "Pre-order" label on the item. The availability API can be used for this by calling it with a product handle or identifier rather than a variant.

### Purchasing pre-order items

Once you've used the availability API to determine the correct state for the item, you need to trigger Purple Dot whenever the Shopper interacts with the Pre-order button via our Checkout API.

For Express this will display an overlay with the first page of the pre-order checkout for the Shopper to buy the item. For separate bag this will display the shoppers pre-order cart where they can add and remove any items before continuing to checkout.

### Shopper self-service

We also provide Shoppers with self-service tools for managing their pre-order such as cancelling items, or updating their payment method. This can be integrated on any page you like within your store using our SDK.

### @purple-dot/browser

Purple Dot provides an [npm package](https://www.npmjs.com/package/@purple-dot/browser) that includes the components needed for the integration. It must be included and initialised whenever the storefront is loaded, likely in the root layout of your storefront application.

```bash
npm install -S @purple-dot/browser
```

```jsx
import * as PurpleDot from '@purple-dot/browser';

PurpleDot.init({
  apiKey: '$YOUR_API_KEY',
});
```

> 💡 Your API key can be found in the Merchant Portal under Settings > Integration.

You can find examples of using the SDK here [github.com/purple-dot/browser-examples](https://www.github.com/purple-dot/browser-examples).

#### @purple-dot/browser/availability

The pre-order availability API should be used for determining if a product or a variant should be displayed as a pre-order and the estimated ship dates if so.

Purple Dot provides a client library that can be used like:

```typescript
import * as PurpleDot from '@purple-dot/browser';
import { availability } from '@purple-dot/browser/availability';

async function inStockInMyStore({ variantId }) {
    const response = await fetch(`/your/api/product.json?variant=${variantId}`);
    const data = response.json();
    
    // Return a truthy value when the item is In Stock.
    
    return data.quantity;
}

const preorderState = await availability({
  variantId: variant.id
}, inStockInMyStore);
```

The `availability` call takes 2 arguments

* `request`: An object with either a `variantId` or `productHandle` property indicating the item to look up the preorder state for.
* `inStockCallback` (optional): A callback used to check if the item is instock against your own inventory system before checking the preorder status.

The result is and object with this shape

* `state`
  * `AVAILABLE_IN_STOCK`
    * The variant is available in stock and should not be sold as a pre-order.
  * `ON_PREORDER`&#x20;
    * The variant is available as a pre-order only.
  * `SOLD_OUT`&#x20;
    * The variant is neither available in stock or on a pre-order.
* `waitlist` (if state is `ON_PREORDER`)
  * `id` - the waitlist ID
  * `display_dispatch_date` - the estimated ship date to display for the variant if on pre-order

#### @purple-dot/browser/checkout

This module provides access to the Purple Dot checkout APIs so that you can open the checkout and items to the separate bag.

To start an Express checkout use&#x20;

`openExpressCheckout(variantId, releaseId, currency, quantity);`

To add an item to the Separate Cart use

`addItem(variantId, releaseId, currency, quantity);`

#### Learn more component

When a variant is on pre-order, the estimated ship dates and the “Pre-order protected by” branding must be displayed near the “Pre-order” call to action. Purple Dot provides a Web Component that can be used with any JS framework.

<p align="center"><img src="https://35070260-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F58PWmT9iYQoKNKYtPSZy%2Fuploads%2FlFIvIS2El4jH22whQDdj%2Fimage.png?alt=media&amp;token=32aba299-d017-43b2-97dd-98953f6185a0" alt=""></p>

Simply place a `<purple-dot-learn-more />` HTML element near the Pre-order button.

#### Separate pre-order bag

When using the Separate Bag checkout you will probably want to show the shopper a separate pre-order cart next to your normal in stock item cart in your navigation. To support this we provide a `<purple-dot-separate-bag />` component which can be customised to fit the look and feel of your store.

This component comes with some default styling but you are free to add your own elements inside it which will override our defaults. The element will automatically have some attributes to help you style it as desired.

* The `data-item-count` attribute will always be set to the current number of items in the pre-order cart.
* When the shopper has pre-order items in the cart `class="purple-dot-separate-bag--has-items"` will be added to the element.

You should use these to do things like hide the separate cart element when the cart is empty, or to indicate the number of items in the bag to the shopper.

#### Shopper self-service portal component

Purple Dot provides a portal where shoppers can manage their pre-orders. The portal can be embedded onto any page in your storefront:

1. Create a new page that can host the portal, e.g. `/account/manage-pre-orders`
2. Place a `<purple-dot-self-service />` component where you would like the self service iframe to appear. This component is framework-agnostic and is compatible with all popular frameworks like React and Vue.


# Public API

### [Overview](#webhooks) <a href="#webhooks" id="webhooks"></a>

This reference documents the public API that can be used to get information about Waitlists and product availability, both server- and client-side.

### [Authentication](#authentication) <a href="#authentication" id="authentication"></a>

Include your store's public API key as an `api_key` query parameter in all requests.

### [Versioning](#versioning) <a href="#versioning" id="versioning"></a>

The API is versioned using a URL prefix. The current version is `v1`, and all endpoints use the `/api/v1/` namespace.

### [Response Format](#response-format) <a href="#response-format" id="response-format"></a>

All responses follow a common format:

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": /* Response data */
}
```

{% endcode %}

### [Endpoints](#endpoints) <a href="#endpoints" id="endpoints"></a>

[/waitlists](/docs/purple-dot-apis/public-api/waitlists)

[/availability](/docs/purple-dot-apis/public-api/availability)

[/products/preorder-state](/docs/purple-dot-apis/public-api/products-preorder-state)

[/variants/preorder-state](/docs/purple-dot-apis/public-api/variants-preorder-state)

[/pre-orders](/docs/purple-dot-apis/public-api/pre-orders)


# /waitlists

#### [`GET /waitlists`](#get-waitlists) <a href="#get-waitlists" id="get-waitlists"></a>

Get all open Waitlists. Useful for determining which products have a Waitlist.

Request query parameters:

* `api_key` - Required. Your Purple Dot store's public API key

Response:

* `data` - An array containing all the open Waitlists
  * `id` - The Waitlist ID
  * `state` - one of:
    * `SCHEDULED` - to start selling pre-orders, stock levels and [Operations settings inside Purple Dot](https://www.purpledotprice.com/merchant-portal) permitting, from `launch_date`
    * `OPEN` - is now selling pre-orders, stock levels and Operations settings permitting
    * `PAUSED` - non terminal state, can be made `OPEN` in the future
    * `CLOSED` - terminal state, will not change again
  * `display_dispatch_date` - The Waitlist estimated shipping dates
  * `payment_plan_descriptions` - (platform integrations only, otherwise `null`) Shopper friendly description of your store's pre-order payment plan, if any
  * `selling_plan_id` - (Shopify app integrations only, otherwise `null`) The Shopify ID of the selling plan linked to this Waitlist
  * `is_scheduled` - If this Waitlist is yet to go live in your storefront
  * `launch_date`:  The date this Waitlist goes live in your storefront
  * `product` - An object containing the Waitlisted product
    * `id` - The ID of the product used by the connected store, e.g. Shopify `product.id`
    * `product_code` - The product code used by the connected store, e.g. Shopify `product.handle`

Examples:

```bash
curl --request GET \
  --url 'https://www.purpledotprice.com/api/v1/waitlists?api_key=<...>
```

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": [
    {
      "id": "3bbc58c6-9a11-422f-9cf5-6a5ac8468eec",
      "state": "OPEN",
      "display_dispatch_date": "Shipping 10–15 Jun",
      "payment_plan_descriptions": null,
      "selling_plan_id": null,
      "product": {
        "id": "4697179062404",
        "product_code": "womens-white-sneakers"
      }
    }
  ]
}
```

{% endcode %}


# /availability

#### [`GET /availability`](#get-availability) <a href="#get-availability" id="get-availability"></a>

Get the Purple Dot stock levels for a product and all its variants. Useful for determining whether a particular variant has stock available in Purple Dot.

Request query parameters:

* `api_key` - Required. Your Purple Dot store's public API key
* `product_id`- Required. The ID of the product used by the connected store, e.g. Shopify `product.id`

Response:

* `data`
  * `id` - The ID of the product used by the connected store, e.g. Shopify `product.id`
  * `product_code` - The product code used by the connected store, e.g. Shopify `product.handle`
  * `available` - Boolean indicating whether the product has any remaining Waitlist stock
  * `available_stock` - The number of units (across all variants) that are available on the Waitlist
  * `variants` - An array containing all the product's variants
    * `id` - The ID of the product used by the connected store, e.g. Shopify `variant.id`
    * `sku` - The SKU used by the connected store, e.g. Shopify `variant.sku`
    * `available` - Boolean indicating whether this variant has any remaining Waitlist stock
    * `available_stock` - The number of units available for this variant on the Waitlist
    * `available_in_stock` - Purple Dot's view of the number of units available for this variant in your Shopify store
    * `oversell_enabled` - Boolean indicating Purple Dot's view if this variant has its [inventory\_policy](https://shopify.dev/docs/api/admin-rest/2022-07/resources/product-variant) set to `continue` in Shopify. Should be `true` for any variant in a store using the [Combined Cart](https://docs.getpurpledot.com/docs/platform-integration-with-shopify/integrate-with-shopify-using-liquid-templates#5.-setup-your-preferred-checkout-method) checkout type if this variant has Waitlist stock and that Waitlist is live
    * `waitlist_id` - Purple Dot's internal ID of the Waitlist that has stock of this variant, if any

Examples:

```bash
curl --request GET \
  --url 'https://www.purpledotprice.com/api/v1/availability?product_id=4697179062404&api_key=<...>'
```

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": {
    "id": "4697179062404",
    "product_code": "womens-white-sneakers",
    "available": true,
    "available_stock": 500,
    "variants": [
      {
        "id": "32813576749188",
        "sku": "PD3-10",
        "available": true,
        "available_stock": 500,
        "available_in_stock": 0,
        "oversell_enabled": true,
        "waitlist_id": "578a2f72-bbd9-41e1-9330-7eb3ba190f00",
      },
      {
        "id": "32813576388740",
        "sku": "PD3-5",
        "available": false,
        "available_stock": 0
        "available_in_stock": 0
        "oversell_enabled": false,
        "waitlist_id": null,
      }
    ]
  }
}
```

{% endcode %}


# /products/preorder-state

#### [`GET /products/preorder-state`](#get-availability) <a href="#preorder-state-products" id="preorder-state-products"></a>

Get the pre-order state of a whole product. Useful for determining whether a particular product as a whole is on pre-order, for example when displaying a product in a collection grid.

Request query parameters:

* `api_key` - Required. Your Purple Dot store's public API key
* `handle`- Required. The Shopify handle of the product
* `country` - Optional. The country shopper is in

Response:

* `data`
  * `state` - One of:
    * `NO_OPEN_WAITLISTS` - there is no live or scheduled Waitlist inside Purple Dot for this product
    * `AVAILABLE_IN_STOCK` - when at least 1 variant is `AVAILABLE_IN_STOCK`
    * `ON_PREORDER` - when none of the variants are `AVAILABLE_IN_STOCK` but at least 1 variant is `ON_PREORDER`
    * `SOLD_OUT` - when all variants are `SOLD_OUT`
  * `waitlist` - The product's waitlist or `null` if there isn't an open waitlist.
    * `display_dispatch_date` - The string that should be shown as the estimated dispatch date for the product.
  * `product` - The product that the variant belongs to.
    * `handle` - The product's Shopify handle.

Examples:

```bash
curl --request GET \
  --url 'https://www.purpledotprice.com/api/v1/products/preorder-state?api_key=<...>&handle=womens-white-sneakers'
```

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": [
    {
      "state": "ON_PREORDER",
      "waitlist": {
        "id": "00fe49ba-8e43-4b10-9588-dccaa30f19ac",
        "display_dispatch_date": "Estimated ship date 10–15 Jun",
        "payment_plan_descriptions": null,
        "selling_plan_id": null,
      },
      "product": {
        "id": "4697179062404",
        "product_code": "womens-white-sneakers"
      }
    }
  ]
}
```

{% endcode %}


# /variants/preorder-state

#### [`GET /variants/preorder-state`](#get-availability) <a href="#preorder-state-variants" id="preorder-state-variants"></a>

Get the pre-order state of a variant. Useful for determining whether a particular variant is on pre-order, for example when displaying a call to action on the PDP.

Request query parameters:

* `api_key` - Required. Your Purple Dot store's public API key
* `variant_id`- Required. The Shopify variant id of the product variant
* `country` - Optional. The country shopper is in

Response:

* `data`
  * `state` - One of:
    * `NO_OPEN_WAITLISTS` - there is no live or scheduled Waitlist inside Purple Dot for this variant
    * `AVAILABLE_IN_STOCK` - there is a live or scheduled Waitlist inside Purple Dot but the variant is not selling as a pre-order because one of your Shopify locations has stock for it and the [Operations settings inside Purple Dot](https://www.purpledotprice.com/merchant-portal) to "Watch inventory levels in Shopify" dictate that this should be cleared down first before this variant starts to sell as a pre-order.
    * `ON_PREORDER` - the variant will sell as a pre-order, either because you have
      * no stock in your own Shopify locations and some stock on a live Waitlist
      * you have some stock in your own Shopify locations but set your Operations settings inside Purple Dot to not "Watch inventory levels in Shopify"
    * `SOLD_OUT` - there is no stock remaining for this variant, neither in your own Shopify locations, nor on any Waitlist
  * `waitlist` - The product's waitlist or `null` if there isn't an open waitlist.
    * `display_dispatch_date` - The string that should be shown as the estimated dispatch date for the product.
  * `product` - The product that the variant belongs to.
    * `handle` - The product's Shopify handle.

Examples:

```bash
curl --request GET \
  --url 'https://www.purpledotprice.com/api/v1/variants/preorder-state?api_key=<...>&variant_id=55391387124086'
```

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": {
    "state": "ON_PREORDER",
    "waitlist": {
      "id": "00fe49ba-8e43-4b10-9588-dccaa30f19ac",
      "is_scheduled": false,
      "launch_date": null,
      "selling_plan_id": null,
      "display_dispatch_date": "Estimated ship date 1–8 Jul",
      "payment_plan_descriptions": null,
      "use_extended_delivery_language": false,
      "units_left": 1
    },
    "product": {
      "id": "15121333223798",
      "handle": "the-complete-snowboard"
    }
  }
}
```

{% endcode %}


# /pre-orders

### [Authentication](#authentication)

As well as including your store's public API key as an `api_key` query parameter in all requests, this endpoint requires a few other parameters:&#x20;

<table><thead><tr><th width="200.48046875">Query param</th><th>Where to find it</th></tr></thead><tbody><tr><td><code>api_key</code></td><td>This is available on the <a href="https://www.purpledotprice.com/merchant-portal/integration">integration</a> page on your merchant portal under 'Public API Key'</td></tr><tr><td><code>email</code></td><td>This is the email of the shopper you're looking up the info for</td></tr><tr><td><code>timestamp</code></td><td>This is the browser timestamp in the epoch format</td></tr><tr><td><code>token</code></td><td>This is the security signature that Purple Dot uses to verify the authenticity of the request. This is generated by hashing the <code>email</code> and the <code>timestamp</code> against the 'Shared secret' found on the <a href="https://www.purpledotprice.com/merchant-portal/integration">integration</a> page. More on how to generate this token <a href="#how-to-generate-the-token">below</a>.</td></tr></tbody></table>

#### How to generate the `token`

Purple Dot expects a SHA-256 hash of the `email` and the `timestamp` in the following format:

&#x20;`<email>:<timestamp>`

This allows us to verify the integrity and authenticity of the request by having it securely assigned using a shared secret. The generated token will only be valid for 10 seconds within the timestamp; to make the same API call for updated data, a new token must be generated.

You can generate the token within a Shopify theme in a `.liquid` file as shown below:

```liquid
{% assign timestamp = 'now' | date: '%s' %}
{% assign token_value = customer.email | append: ':' | append: timestamp %}
{% assign token = token_value | hmac_sha256: 'YOUR_SHARED_SECRET' %}

<script>
  window.PurpleDotAPICredentials = {
    timestamp: "{{ timestamp }}",
    email: "{{ customer.email }}",
    token: "{{ token }}"
  }
</script>
```

To generate the token using Javascipt and the native [browser `crypto` APIs](https://developer.mozilla.org/en-US/docs/Web/API/Crypto), you can add the following `<script>` to an HTML file:

```javascript
<script>
  async function generateHmacSha256(secret, data) {
    const encoder = new TextEncoder();

    const key = await crypto.subtle.importKey(
      "raw",
      encoder.encode(secret),
      { name: "HMAC", hash: "SHA-256" },
      false,
      ["sign"]
    );

    const signature = await crypto.subtle.sign(
      "HMAC",
      key,
      encoder.encode(data)
    );

    const hexString = Array.from(new Uint8Array(signature), (byte) =>
      byte.toString(16).padStart(2, "0")
    ).join("");

    return hexString;
  }

  async function fetchPreordersForEmail(email) {
    const apiKey = 'YOUR_API_KEY';
    const sharedSecret = 'YOUR_SHARED_SECRET';

    const timestamp = Math.floor(Date.now() / 1000); // convert milliseconds to seconds
    const tokenData = `${email}:${timestamp}`;
    const token = await generateHmacSha256(sharedSecret, tokenData);

    const url = new URL("https://www.purpledotprice.com/api/v1/pre-orders");
    url.searchParams.append("api_key", apiKey);
    url.searchParams.append("email", email);
    url.searchParams.append("timestamp", timestamp);
    url.searchParams.append("token", token);

    const response = await fetch(url.toString(), {
      headers: {
        "Content-Type": "application/json",
      },
    });

    if (response.ok) {
      return response.json();
    }
  }

  fetchPreordersForEmail("customer@example.com").then((preorders) => {
    console.log(preorders);
  });
</script>
```

If testing this in an API tool like Postman, you can generate the token using a pre-request script. Within Postman, you can import the `crypto-js` library, which simplifies some of the token generation&#x20;

```javascript
const crypto = require('crypto-js');

const API_KEY = 'YOUR_API_KEY';
const SHARED_SECRET = 'YOUR_SHARED_SECRET';

const email = 'customer@example.com';
const timestampInSeconds = Math.floor(Date.now() / 1000);
const tokenValue = `${email}:${timestampInSeconds}`;

const hash = crypto.HmacSHA256(tokenValue, SHARED_SECRET);
const token = crypto.enc.Hex.stringify(hash);

pm.request.addQueryParams(`api_key=${API_KEY}&token=${token}&timestamp=${timestampInSeconds}&email=${email}`);
```

#### [`GET /pre-orders`](#get-pre-orders)

Get all pre-orders for a given shopper email address.

Request:

* `limit` (number) - Optional. The number of pre-orders to retrieve. Set to 10 by default but can be set up to 100
* `starting_after` (UUID) - Optional. Paginate pre-orders after the given pre-order ID

Response:

* `orders` - An array containing all the pre-orders
  * `id` - The Purple Dot ID of the pre-order
  * `reference` - The Purple Dot reference number of the pre-order
  * `created_at` - ISO8610 timestamp of when the pre-order was placed
  * `total_amount` - The pre-order total
  * `currency` - The presentment currency of the pre-order
  * `line_items` - Array of line items
    * `id` - The Purple Dot ID of the line item
    * `estimated_ship_dates` - The estimated ship dates of the line item
    * `product_id` - The Shopify ID of the line item's product
    * `variant_id` - The Shopify ID of the line item's product variant
    * `order_id` - The Shopify order ID in  (this will be `null` if the preorder/line-item is not exported to Shopify)
    * `cancelled` - Whether the line item is cancelled
  * `shipping_address`
    * `first_name`
    * `last_name`
    * `address1`
    * `address2`
    * `city`
    * `postal_code`
    * `province_code` - The ISO3166 code of the second level administrative subdivision
    * `country_code` - The ISO3166 code of the country
    * `phone`
* `has_more` - Indicates whether there are more pre-orders available to page through
* `starting_after` - The ID of the last pre-order in the list which can then be used in the next request

Examples:

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://www.purpledotprice.com/api/v1/pre-orders?api_key=<<enter-api-key>>&email=<<enter-email>>&timestamp=<<enter-timestamp>>&token=<<enter-generated-token>>'
```

{% endcode %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": {
    "pre_orders": [
      {
        "id": "03cda1e6-0827-4092-ae97-5a4746bac0b3",
        "reference": "#PD404821",
        "created_at": "2023-12-07T10:59:24.248Z",
        "total_amount": 54.72,
        "currency": "USD",
        "line_items": [
          {
            "id": "628f7e83-c56f-4e16-9959-43e011f77e8f",
            "estimated_ship_dates": "Mar 1 – 2",
            "product_id": "9f32f1f6-42bc-49f3-8a55-d28362444ccf",
            "variant_id": "9c1206a0-7efa-43af-bbfa-52498f6af6aa",
            "order_id": null,
            "canceled": false
          }
        ],
        "shipping_address": {
          "first_name": "John",
          "last_name": "Smith",
          "address1": "8 York Road",
          "address2": null,
          "city": "London",
          "postal_code": "SW49 5LT",
          "province_code": null,
          "country_code": "GB",
          "phone": "+441974616161"
        }
      }
    ],
    "has_more": true,
    "starting_after": "2174855e-0f3c-482d-9cf0-f2b5cb6213cf"
  }
}
```


# Private API

### [Overview](#webhooks) <a href="#webhooks" id="webhooks"></a>

This reference documents the private API that can be used to access private data in Purple Dot.

### [Authentication](#authentication) <a href="#authentication" id="authentication"></a>

Include your Purple Dot store's private access token as `X-Purple-Dot-Access-Token` header in all requests.

### [Versioning](#versioning) <a href="#versioning" id="versioning"></a>

The API is versioned using a URL prefix. The current version is `v1`, and all endpoints use the `/admin/api/v1/` namespace.

### [Response Format](#response-format) <a href="#response-format" id="response-format"></a>

All responses follow a common format:

{% code overflow="wrap" %}

```json
{
  "meta": {
    "success": true
  },
  "data": /* Response data */
}
```

{% endcode %}

### [Endpoints](#endpoints) <a href="#endpoints" id="endpoints"></a>

[/waitlists](/docs/purple-dot-apis/private-api/waitlists)

[/pre-orders](/docs/purple-dot-apis/private-api/pre-orders)

[/pre-orders/count](/docs/purple-dot-apis/private-api/pre-orders-count)

[/pre-orders/count-units/sku/:sku](/docs/purple-dot-apis/private-api/pre-orders-count-units-sku-sku)

[/inventory](/docs/purple-dot-apis/private-api/inventory)

[/fulfillment-orders](/docs/purple-dot-apis/private-api/fulfillment-orders)

[/fulfillment-orders/:id(uuid)](/docs/purple-dot-apis/private-api/fulfillment-orders-id-uuid)

[/fulfillment](/docs/purple-dot-apis/private-api/fulfillment)

[/refund](/docs/purple-dot-apis/private-api/refund)

####


# /waitlists

#### GET /admin/api/v1/waitlists <a href="#get-pre-orders" id="get-pre-orders"></a>

Request:

* `limit` (number) - Optional. The number of waitlists to retrieve. Set to 10 by default but can be set up to 100
* `created_at_min` (ISO8610 timestamp) - Optional. List waitlists created since the given time
* `updated_at_min` (ISO8610 timestamp) - Optional. List waitlists updated since the given time
* `starting_after` (UUID) - Optional. Paginate pre-orders after the given waitlist ID

Headers:

* `Link` - An IETF [RFC 8288](https://datatracker.ietf.org/doc/html/rfc8288#section-2) compliant header with links to previous and next page of results for the preorder query.

Body:

* `waitlists` - An array containing waitlists
  * `id` - ID used to identify the waitlist inside Purple Dot
  * `created_at` - ISO8610 timestamp of when the waitlist was created
  * `updated_at` - ISO8610 timestamp of when the waitlist was last updated
  * `earliest_ship_date` - ISO8610 timestamp of the earliest date the waitlisted product can ship
  * `latest_ship_date` - ISO8610 timestamp of the latest date the waitlisted product can ship
  * `state` - The state of the waitlist. This can be one of the following:
    * `LIVE` - Shoppers can start placing preorders for this product if there is no stock in Shopify
    * `PAUSED` - Shoppers cannot place preorders for this product until the waitlist is unpaused
    * `CLOSED` - Waitlist is now closed
    * `SCHEDULED` - Waitlist will be live on the launch date
    * `DRAFT` - Waitlist is in draft state and needs approval before going live
  * `launch_date` - ISO8610 timestamp of when the waitlist will be live
  * `scheduled_pause_date` - ISO8610 timestamp of when the waitlist will be paused
  * `labels` - Labels associated with the waitlist
  * `availability` - A map of the product & variant-wise sales data
    * `product` - Sales data for the product
      * `product_id` - Shopify ID for the product
      * `buy_size` - Total number of units allocated for preorder
      * `committed` - Total number of preorder units sold
      * `available` - Total number of preorder units available for sale
    * `variants` - An array of the sales data for all the product variants
      * `variant_id` - Shopify ID of the product variant
      * `sku` - SKU code of the product variant
      * `buy_size` - Total number of units of the product variant allocated for preorder (this will be null in the case of a per-product waitlist)
      * `committed` - Total number of preorder units of the product variant sold
      * `available` - Total number of preorder units available of the product variant for sale (this will be null in the case of a per-product waitlist)
* `starting_after` - The ID of the last waitlist in the list which can then be used in the next request
* `has_more` - Indicates whether there are more orders available to page through

Examples:

```bash
curl --request GET \
     --url 'https://www.purpledotprice.com/admin/api/v1/waitlists?limit=1&created_at_min=2023-08-17T00:00:00.000Z' \
     --header 'X-Purple-Dot-Access-Token: <access_token>'
```

<details>

<summary>This is what a per-variant waitlist response would look like:</summary>

```json
{
  "meta":{
    "result":"success"
  },
  "data":{
    "waitlists":[
      {
        "id":"a2aecc56-ce64-49da-8ce6-099e664d85fd",
        "created_at":"2023-10-27T14:44:09.726Z",
        "earliest_ship_date":"2023-11-25T05:00:00.000Z",
        "latest_ship_date":"2023-12-10T04:59:59.999Z",
        "state":"CLOSED",
        "launch_date":"2023-12-10T00:00:00.000Z",
        "labels":[
          
        ],
        "availability":{
          "product":{
            "product_id":"7257265143861",
            "buy_size":10,
            "committed":3,
            "available":10
          },
          "variants":[
            {
              "variant_id":"42662551519285",
              "sku":"ZTEST",
              "buy_size":10,
              "committed":3,
              "available":10
            }
          ]
        }
      }
    ],
    "has_more":true,
    "starting_after":"a2aecc56-ce64-49da-8ce6-099e664d85fd",
    "previous_cursor":"0c34fc59-8a99-427f-a340-857e1eb9b6d2"
  }
}
```

</details>

<details>

<summary>This is what a per-product waitlist response would look like:</summary>

```json
{
  "meta":{
    "result":"success"
  },
  "data":{
    "waitlists":[
      {
        "id":"c657585b-bfe0-4aca-867d-e2c3399969a3",
        "created_at":"2023-09-20T16:57:55.928Z",
        "earliest_ship_date":"2024-04-08T04:00:00.000Z",
        "latest_ship_date":"2024-04-19T04:00:00.000Z",
        "state":"CLOSED",
        "launch_date":null,
        "labels":[
          
        ],
        "availability":{
          "product":{
            "product_id":"7233472626741",
            "buy_size":10,
            "committed":4,
            "available":10
          },
          "variants":[
            {
              "variant_id":"42591503876149",
              "sku":"TEST-S",
              "buy_size":null,
              "committed":2,
              "available":null
            },
            {
              "variant_id":"42591503843381",
              "sku":"TEST-M",
              "buy_size":null,
              "committed":1,
              "available":null
            },
            {
              "variant_id":"42591503777845",
              "sku":"TEST-L",
              "buy_size":null,
              "committed":1,
              "available":null
            }
          ]
        }
      }
    ],
    "has_more":true,
    "starting_after":"c657585b-bfe0-4aca-867d-e2c3399969a3",
    "previous_cursor":null
  }
}
```

</details>

#### POST /admin/api/v1/waitlists (Preview)

Creates a new waitlist. Fails with `409 Conflict` if a waitlist already exists for the same product and ship date range.

**Request Body**

* `product_id` (string, required) — External product ID; the numeric suffix as a string (e.g. `"123"`)
* `earliest_ship_date` (string, required) — ISO 8601 date; earliest expected ship date
* `latest_ship_date` (string, required) — ISO 8601 date; latest expected ship date
* `max_units` (array, required) — Per-SKU max units; at least one entry required. Each entry:
  * `sku_id` (string, required) — External SKU/variant ID; the numeric suffix as a string (e.g. `"456"`)
  * `max_units` (number, required) — Maximum units for this SKU (non-negative integer)
* `state` (string, required) — One of: `OPEN`, `PAUSED`, `CLOSED`, `DRAFT`
* `labels` (array, required) — Array of label strings (can be empty)

**Example Request**

```json
{
  "product_id": "123",
  "earliest_ship_date": "2025-03-01",
  "latest_ship_date": "2025-03-15",
  "max_units": [
    { "sku_id": "456", "max_units": 50 },
    { "sku_id": "789", "max_units": 30 }
  ],
  "state": "OPEN",
  "labels": ["spring-2025"]
}
```

**Response** `201 Created`

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "product_id": "123",
  "state": "OPEN",
  "earliest_ship_date": "2025-03-01T00:00:00.000Z",
  "latest_ship_date": "2025-03-15T00:00:00.000Z",
  "max_units": [
    { "sku_id": "456", "max_units": 50 },
    { "sku_id": "789", "max_units": 30 }
  ],
}
```

**Errors**

* `400 Bad Request` — Invalid or missing required fields
* `404 Not Found` — Product or variant not found for the store
* `409 Conflict` — A waitlist already exists for this product and ship dates

***

#### PUT /admin/api/v1/waitlists (Preview)

Creates a new waitlist or updates an existing one, matched by product and ship date range. If a matching waitlist exists, it is updated; otherwise a new one is created.

**Request Body**

Same as Create Waitlist.

**Response** `200 OK`

Same structure as the Create response. Returns the created or updated waitlist.

**Errors**

* `400 Bad Request` — Invalid or missing required fields
* `404 Not Found` — Product or variant not found for the store

***

#### PUT /admin/api/v1/waitlists/:releaseId (Preview)

Updates an existing waitlist by its ID. Use this when you know the waitlist's `id` (e.g. from a previous create/upsert or list response).

**URL Parameters**

* `releaseId` (string) — UUID of the waitlist to update

**Request Body**

Same as Create Waitlist. The `product_id` in the body must match the waitlist's current product.

**Example Request**

```
PUT /waitlists/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
```

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "product_id": "123",
  "earliest_ship_date": "2025-03-01",
  "latest_ship_date": "2025-03-20",
  "max_units": [
    { "sku_id": "456", "max_units": 75 }
  ],
  "state": "PAUSED",
  "labels": ["spring-2025", "delayed"]
}
```

**Response** `200 OK`

Same structure as the Create response.

**Errors**

* `400 Bad Request` — Invalid fields or `product_id` does not match the waitlist
* `404 Not Found` — Waitlist not found, or belongs to another store


# /pre-orders

#### [`GET /pre-orders`](#list-all-pre-orders) <a href="#get-pre-orders" id="get-pre-orders"></a>

#### List all pre-orders.

Note for customers using our platform integration with combined cart: this data does not include in-stock purchases that went through Purple Dot's checkout.

Request:

* `limit` (number) - Optional. The number of pre-orders to retrieve. Set to 10 by default but can be set up to 200
* `created_at_min` (ISO8610 timestamp) - Optional. List pre-orders created since the given time
* `updated_at_min` (ISO8610 timestamp) - Optional. List pre-orders updated since the given time
* `updated_at_max` (ISO8610 timestamp) - Optional. List pre-orders updated no sooner than the given time
* `references` (string) - Optional. Comma separated list of (URL-encoded) Purple Dot order references
* `skus` (string) - Optional. Comma separated list of product variant SKUs
* `email` (string) - Optional. List pre-orders placed by the given email
* `all_line_items` (string) - Optional. List pre-orders where every line item is any of these comma separated states. Currently supported are `cancelled` and `exported`
* `some_line_item` (string) - Optional. List pre-orders where at least 1 line item is any of these comma separated states. Currently supported are `cancelled` and `exported`. Cannot be used in conjunction with `all_line_items`
* `starting_after` (UUID) - Optional. Paginate pre-orders after the given pre-order ID

Headers:

* `Link` - An IETF [RFC 8288](https://datatracker.ietf.org/doc/html/rfc8288#section-2) compliant header with links to previous and next page of results for the pre-order query.

Body:

* `orders` - An array containing pre-orders
  * `id` - ID used to identify the pre-order inside Purple Dot
  * `reference` - The Purple Dot order reference, the same as shared with the shoppers
  * `currency` - The presentment currency of the order
  * `created_at` - ISO8610 timestamp of when the pre-order was placed
  * `cancelled_at` -  ISO8610 timestamp of when the whole order was canceled (null if not canceled)
  * `cancel_reason` - The reason for the cancelation
  * `customer`
    * `email` - The customer's email address
    * `external_id` - The Shopify ID of this customer, if we know it
  * `line_items` - Array of line items
    * `id` - The Purple Dot ID of the line item
    * `name` - The name of the product variant in this line item
    * `sku` - The SKU code of the product variant in this line item
    * `product_id` - The Shopify ID of the line item's product
    * `variant_id` - The Shopify ID of the line item's product variant
    * `waitlist_id` - The Purple Dot ID of the Waitlist this line item sold from. Could be null if the line item was in-stock at the time of sale but it was held back to ship with other line items that were on pre-order
    * `quantity` - The quantity of the line item
    * `price` - The total cost of this line item, before taxes/discounts etc
    * `unit_price` - `price` divided by `quantity`
    * `taxable` - Whether the product variant in this line item is taxable
    * `tax_lines` - The taxes applied to the line item
      * `price`  - The total amount of tax for the line item
      * `rate`  - The tax rate as a decimal
      * `title`  - The name of the tax
      * `inclusive`  - Whether this tax is already included in the line item price
    * `total_discount` - The total amount of discounts applied to the line item
    * `total` - The total cost of this line item, after tax/discounts etc
    * `unit_total` - `total` divided by `quantity`
    * `earliest_ship_date` - ISO8610 timestamp of the earliest date this line item is expected to ship
    * `latest_ship_date` - ISO8610 timestamp of the latest date this line item is expected to ship
    * `cancelled` - If this line item has been canceled
    * `cancelled_at` -  ISO8610 timestamp of when the whole order was canceled (null if not canceled)
  * `shipping_address`
    * `first_name`
    * `last_name`
    * `address1`
    * `address2`
    * `city`
    * `postal_code`
    * `province_code` - The ISO3166 code of the second level administrative subdivision
    * `country` - The English name of the country
    * `country_code` - The ISO3166 code of the country
    * `phone`
  * `shipping_lines` - An array of shipping rates
    * `id` - The Purple Dot ID of the shipping line
    * `price` - The unit cost of this shipping line, before taxes/discounts etc
    * `total`- The total cost of this shipping line, after tax/discounts etc are considered
    * `title` - The user-facing name of the shipping rate
    * `code` - The shipping rate carrier code
    * `tax_lines` - The taxes applied to the shipping rate
      * `price`  - The total amount of tax for the shipping line
      * `rate`  - The tax rate as a decimal
      * `title`  - The name of the tax
      * `inclusive`  - Whether this tax is already included in the shipping line price
    * `line_items` - The line items this shipping rate applies to
      * `line_item_id` - The Purple Dot ID of the line item
  * `subtotal_price` - The total of the line items before taxes and shipping
  * `total_discounts` - The total discounts applied to the pre-order
  * `total_tax` - The total tax on the pre-order
  * `tax_included` - Whether the tax is included in listed prices or not
  * `tax_lines` - All the taxes applied to the pre-order
    * `price`
    * `rate`
    * `title`
  * `total_price` - The pre-order total
  * `total_refunded` - The total of all refunds issued from this pre-order
  * `exported_orders` - Any orders that were exported to Shopify from this pre-order
    * `id` - The Shopify ID of the order that was exported
    * `order_number` - The Shopify order number
    * `created_at` - ISO8610 timestamp of when this external order was created
    * `line_items` - The pre-order line items that were exported
      * `id` - The Shopify ID of the line item
      * `line_item_id` - The Purple Dot ID of the line item
  * `sales_channel` - This can be "online" or "pos"
  * `pos_sale` - This is available if the order was placed through Purple Dot POS&#x20;
    * `staff_name` - The member of staff who completed the sale
    * `location_name` - The Shopify location name where the order was placed
* `starting_after` - The ID of the last pre-order in the list which can then be used in the next request
* `has_more` - Indicates whether there are more pre-orders available to page through

Examples:

{% code overflow="wrap" %}

```
curl --request GET \
     --url 'https://www.purpledotprice.com/admin/api/v1/pre-orders?created_at_min=2023-08-17T00:00:00.000Z&references=%23PD325376&all_line_items=cancelled&skus=TEST1&limit=1' \
     --header 'X-Purple-Dot-Access-Token: <access_token>'
```

{% endcode %}

<pre class="language-json" data-overflow="wrap"><code class="lang-json"><strong>{
</strong>  "meta": {
    "result": "success"
  },
  "data": {
    "orders": [
      {
        "id": "58da51c9-9b48-48c6-beb5-46bd34834960",
        "reference": "#PD2850312",
        "cancel_reason": null,
        "cancelled_at": null,
        "created_at": "2024-11-14T16:18:25.635Z",
        "currency": "USD",
        "email": "test@getpurpledot.com",
        "customer": {
          "email": "test@getpurpledot.com",
          "external_id": "7287702192181"
        },
        "line_items": [
          {
            "id": "55bedf52-ccf0-431a-a75b-2e999e93a5da",
            "total": 26.01,
            "price": 39.99,
            "product_id": "6914583167029",
            "quantity": 1,
            "sku": "PS4-GRVN",
            "variant_id": "41125120573493",
            "name": "Test Product 1",
            "earliest_ship_date": "2025-03-01T05:00:00.000Z",
            "latest_ship_date": "2025-03-31T04:00:00.000Z",
            "taxable": true,
            "tax_lines": [
              {
                "price": 2.12,
                "rate": 0.08875,
                "title": "SALES_TAX",
                "inclusive": false
              }
            ],
            "total_discount": 16.1,
            "cancelled_at": null,
            "cancelled": false,
          },
          {
            "id": "e474a996-d861-41e0-8137-7fc2074dd6a5",
            "total": 22.75,
            "price": 34.99,
            "product_id": "7740980330549",
            "quantity": 1,
            "sku": "P5LR123",
            "variant_id": "44057813581877",
            "name": "Test Product 2",
            "earliest_ship_date": null,
            "latest_ship_date": null,
            "taxable": true,
            "tax_lines": [
              {
                "price": 1.85,
                "rate": 0.08875,
                "title": "SALES_TAX",
                "inclusive": false
              }
            ],
            "total_discount": 14.09,
            "cancelled_at": "2024-11-14T16:20:39.796Z",
            "cancelled": true
          }
        ],
        "shipping_address": {
          "address1": "10 Test Road",
          "address2": "",
          "city": "New York",
          "country": "United States",
          "country_code": "US",
          "first_name": "Test",
          "last_name": "Testington",
          "phone": "+19172756975",
          "province_code": "NY",
          "postal_code": "10463"
        },
        "shipping_lines": [
          {
            "id": "6dfe69ca-ba0e-5af5-864c-693982161631",
            "code": "usps_1058",
            "total": 3.9000000000000004,
            "price": 5.98,
            "title": "Calculated Shipping Rate",
            "tax_lines": [
              {
                "price": 0.32,
                "rate": 0.08875,
                "title": "SALES_TAX",
                "inclusive": false
              }
            ],
            "line_items": [
              {
                "line_item_id": "e474a996-d861-41e0-8137-7fc2074dd6a5"
              }
            ]
          },
          {
            "id": "ca1dc988-7078-5f95-b1a8-3c0722d41ba4",
            "code": "usps_1058",
            "total": 3.88,
            "price": 5.98,
            "title": "Calculated Shipping Rate",
            "tax_lines": [
              {
                "price": 0.31,
                "rate": 0.08875,
                "title": "SALES_TAX",
                "inclusive": false
              }
            ],
            "discount_allocations": [
              {
                "amount": 2.41,
                "discount_application_index": 0
              }
            ],
            "line_items": [
              {
                "line_item_id": "55bedf52-ccf0-431a-a75b-2e999e93a5da"
              }
            ]
          }
        ],
        "subtotal_price": 39.99,
        "tax_lines": [
          {
            "price": 2.12,
            "rate": 0.08875,
            "title": "SALES_TAX"
          }
        ],
        "tax_included": false,
        "total_discounts": 20.91,
        "total_price": 21.2,
        "total_tax": 2.12,
        "total_refunded": 56.54,
        "exported_orders": [
          {
            "id": "5616927408181",
            "created_at": "2024-11-14T16:22:59.432Z",
            "order_number": "#3114029",
            "line_items": [
              {
                "id": "13278614585397",
                "line_item_id": "55bedf52-ccf0-431a-a75b-2e999e93a5da"
              }
            ]
          }
        ],
        "sales_channel": "online",
        "pos_sale": null
      }
    ],
    "starting_after": "58da51c9-9b48-48c6-beb5-46bd34834960",
    "has_more": false,
    "previous_cursor": "935bad68-2726-4ad1-b299-a330650a2bbb"
  }
}
</code></pre>


# /pre-orders/count

#### [`GET /pre-orders/count`](#count-all-pre-orders) <a href="#get-pre-orders" id="get-pre-orders"></a>

#### Count all pre-orders.

Request:

* `created_at_min` (ISO8610 timestamp) - Optional. Count pre-orders created since the given time
* `updated_at_min` (ISO8610 timestamp) - Optional. Count pre-orders updated since the given time
* `updated_at_max` (ISO8610 timestamp) - Optional. Count pre-orders updated no sooner than the given time
* `skus` (string) - Optional. Comma separated list of product variant SKUs
* `email` (string) - Optional. List pre-orders placed by the given email
* `all_line_items` (string) - Optional. Count pre-orders where every line item is any of these comma separated states. Currently supported are `cancelled` and `exported`
* `some_line_item` (string) - Optional. Count pre-orders where at least 1 line item is any of these comma separated states. Currently supported are `cancelled` and `exported`. Cannot be used in conjunction with `all_line_items`

Body:

* `count` - The number of pre-orders that meet the requested criteria

Examples:

{% code overflow="wrap" %}

```
curl --request GET \
     --url 'https://www.purpledotprice.com/admin/api/v1/pre-orders/count?created_at_min=2023-08-17T00:00:00.000Z&all_line_items=cancelled&skus=TEST1&limit=1' \
     --header 'X-Purple-Dot-Access-Token: <access_token>'
```

{% endcode %}

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": {
    "count": 1
  }
}
```

{% endcode %}


# /pre-orders/count-units/sku/:sku

#### [`GET /pre-orders/count-units/sku/:sku`](#count-all-pre-orders) <a href="#get-pre-orders" id="get-pre-orders"></a>

#### Count open, canceled and exported units for the given SKU.

Request:

* `at_time` (ISO8610 timestamp) - Optional. Count open/canceled/exported units as of this timestamp. Defaults to now.

Body:

* `sku` - The SKU code of interest
* `at_time` - ISO8610 timestamp of the count calculation
* `open_units` - The number of units purchased through and still being held in Purple Dot because they are not yet ready for fulfilment. Excludes any units that are canceled or exported. An open unit can become either canceled or exported, not both.
* `canceled_units` - The number of units purchased through and held in Purple Dot that were later canceled (either by the shopper or the merchant).
* `exported_units` - The number of units purchased through Purple Dot that were held in Purple Dot that were later exported to the external eCommerce platform.

Examples:

{% code overflow="wrap" %}

```
curl --request GET \
     --url 'https://www.purpledotprice.com/admin/api/v1/pre-orders/count-units/sku/LRS221?at_time=2023-08-18T09:57:49.576Z' \
     --header 'X-Purple-Dot-Access-Token: <access_token>'
```

{% endcode %}

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": {
    "sku": "LRS221",
    "at_time": "2023-08-18T09:57:49.576Z",
    "open_units": 14,
    "canceled_units": 15,
    "exported_units": 12,
  }
}
```

{% endcode %}


# /inventory

#### [`POST /inventory`](#update-the-available-inventory-used-by-purple-dot-for-exporting-pre-orders)

#### Update the available inventory used by Purple Dot for exporting pre-orders.

Request:

* `sku`  - Required. The SKU for which inventory level is being updated
* `available_units` - Required. The number of units of this SKU that are available

The request indicates the total number of units available, not the change since the last call, and is therefore idempotent.

Response:

* `201 Created` - Indicating the update has been received
* `sku` - The SKU for which the inventory level was updated
* `available_units` - The new number of units available

Examples:

```bash
curl --request POST \
     --url 'https://www.purpledotprice.com/admin/api/v1/inventory' \
     --header 'Content-Type: application/json'
     --header 'X-Purple-Dot-Access-Token: <access_token>'
     --data '{"sku": "foo", "available_units": 1}'
```

{% code overflow="wrap" %}

```json
{
  "data": {
    "sku": "foo",
    "available_units": 1
  }
}
```

{% endcode %}


# /fulfillment-orders

#### `GET /fulfillment-orders`

#### List all fulfillment orders.

Request:

* `limit` (number) - Optional. The number of fulfillment orders to retrieve.  Set to 50 by default but can be set up to 250
* `created_at_min` (ISO8610 timestamp) - Optional. List fulfillment orders created since the given time
* `starting_after` (UUID) - Optional. Paginate fulfillment orders after the given fulfillment order ID
* `references` (string) - Optional. Comma separated list of (URL-encoded) Purple Dot fulfillment order references

Body:

* `fulfillment_orders` - An array containing fulfillment orders across pre-orders that are now fulfillable
  * `id` - The Purple Dot ID of the fulfillment order
  * `status` - The current status of the fulfillment order, which can be one of:
    * `UNFULFILLED` - the order has been placed and is waiting to be fulfilled
    * `FULFILLED` - all items have been fulfilled
    * `VOIDED` - the order was canceled
  * `created_at` (ISO8610 timestamp) - when this fulfillment order was created (effectively, when Purple Dot was told the related line items are ready to be fulfilled)
  * `purchased_at` (ISO8610 timestamp) - the `created_at` of the pre-order this fulfillment order originates from
  * `reference` - The Purple Dot fulfillment order reference, defined as `concat(Purple Dot pre-order reference, fulfillment order index)`
  * `customer` - The customer placing the order
    * `email` - The customer's email address
    * `external_id` - The Shopify ID of this customer, if we know it
    * `first_name`
    * `last_name`
    * `tags` - Shopify tags for the customer
    * `default_address`
      * `first_name`
      * `last_name`
      * `address1`
      * `address2`
      * `city`
      * `postal_code`
      * `province_code` - The ISO3166 code of the second level administrative subdivision
      * `country` - The English name of the country
      * `country_code` - The ISO3166 code of the country
      * `phone`
  * `currency` - The presentment currency of the order
  * `subtotal_price` - The total of the line items before taxes and shipping
  * `total_tax` - The total tax on the pre-order
  * `tax_included` - Whether the tax is included in listed prices or not
  * `total_discounts` - The total discounts applied to the fulfillment order
  * `total_price` - The fulfillment order total
  * `line_items` - Array of line items in this fulfillment order
    * `id` - The Purple Dot ID of the line item
    * `name` - The name of the product variant in this line item
    * `product_id` - The Shopify ID of the line item's product
    * `variant_id` - The Shopify ID of the line item's product variant
    * `sku` - The SKU code of the product variant in this line item
    * `price` - The unit cost of the product variant in this line item, before taxes/discounts etc
    * `quantity` - The quantity of the line item
    * `taxable` - Whether the product variant in this line item is taxable
    * `tax_lines` - The taxes applied to the line item
      * `price`  - The total amount of tax for the line item
      * `rate`  - The tax rate as a decimal
      * `title`  - The name of the tax
      * `inclusive`  - Whether this tax is already included in the line item price
    * `total_discount` - The total amount of discounts applied to the line item
    * `total` - The total cost of this line item, after tax/discounts etc, are considered
  * `shipping_address`
    * `first_name`
    * `last_name`
    * `address1`
    * `address2`
    * `city`
    * `postal_code`
    * `province_code` - The ISO3166 code of the second level administrative subdivision
    * `country` - The English name of the country
    * `country_code` - The ISO3166 code of the country
    * `phone`
  * `shipping_lines` - An array of shipping rates
    * `id` - The Purple Dot ID of the shipping line
    * `price` - The unit cost of this shipping line, before taxes/discounts etc
    * `total`- The total cost of this shipping line, after tax/discounts etc, are considered
    * `title` - The user-facing name of the shipping rate
    * `code` - The shipping rate carrier code
    * `tax_lines` - The taxes applied to the shipping rate
      * `price`  - The total amount of tax for the shipping line
      * `rate`  - The tax rate as a decimal
      * `title`  - The name of the tax
      * `inclusive`  - Whether this tax is already included in the shipping line price
  * `note` - optional notes from the Shopify order
* `starting_after` - The ID of the last fulfillment order in the list, which can then be used in the next request
* `has_more` - Indicates whether there are more fulfillment orders available to page through

Examples:

{% code overflow="wrap" %}

```
curl --request GET \
     --url 'https://www.purpledotprice.com/admin/api/v1/fulfillment_orders?created_at_min=2023-08-17T00:00:00.000Z&limit=1' \
     --header 'X-Purple-Dot-Access-Token: <access_token>'
```

{% endcode %}

{% code overflow="wrap" %}

```json
<incoming...>
```

{% endcode %}

```
curl --request GET \
     --url 'https://www.purpledotprice.com/admin/api/v1/fulfillment_orders?references=#PD12345678/2,#PD87654321/1' \
     --header 'X-Purple-Dot-Access-Token: <access_token>'
```


# /fulfillment-orders/:id(uuid)

#### `GET /fulfillment-orders/:id(uuid)`

#### Fetch a specific fulfillment order.

Body:

* `id` - The Purple Dot ID of the fulfillment order
* `status` -  The current status of the fulfillment order, which can be one of:
  * `UNFULFILLED` - the order has been placed and is waiting to be fulfilled
  * `FULFILLED` - all items have been fulfilled
  * `VOIDED` - the order was canceled
* `created_at` (ISO8610 timestamp) - When this fulfillment order was created (effectively, when Purple Dot was told the related line items are ready to be fulfilled)
* `purchased_at` (ISO8610 timestamp) - the `created_at` of the pre-order this fulfillment order originates from
* `reference` - The Purple Dot fulfillment order reference, defined as `concat(Purple Dot pre-order reference, fulfillment order index)`
* `currency` - The presentment currency of the order
* `customer` - The customer placing the order
  * `email` - The customer's email address
  * `external_id` - The Shopify ID of this customer, if we know it
  * `first_name`
  * `last_name`
  * `tags` - Shopify tags for the customer
  * `default_address`
    * `first_name`
    * `last_name`
    * `address1`
    * `address2`
    * `city`
    * `postal_code`
    * `province_code` - The ISO3166 code of the second level administrative subdivision
    * `country` - The English name of the country
    * `country_code` - The ISO3166 code of the country
    * `phone`
* `tax_included` - Whether the tax is included in listed prices or not
* `total_tax` - The total tax on the pre-order
* `total_discounts` - The total discounts applied to the fulfillment order
* `subtotal_price` - The total of the line items before taxes and shipping
* `total_price` - The fulfillment order total
* `line_items` - Array of line items in this fulfillment order
  * `id` - The Purple Dot ID of the line item
  * `price` - The unit cost of the product variant in this line item, before taxes/discounts etc
  * `total` - The total cost of this line item, after tax/discounts etc are considered
  * `taxable` - Whether the product variant in this line item is taxable
  * `tax_lines` - The taxes applied to the line item
    * `price`  - The total amount of tax for the line item
    * `rate`  - The tax rate as a decimal
    * `title`  - The name of the tax
    * `inclusive`  - Whether this tax is already included in the line item price
  * `total_discount` - The total amount of discounts applied to the line item
  * `quantity` - The quantity of the line item
  * `product_id` - The Shopify ID of the line item's product
  * `variant_id` - The Shopify ID of the line item's product variant
  * `sku` - The SKU code of the product variant in this line item
  * `name` - The name of the product variant in this line item
* `shipping_address`
  * `first_name`
  * `last_name`
  * `address1`
  * `address2`
  * `city`
  * `postal_code`
  * `province_code` - The ISO3166 code of the second level administrative subdivision
  * `country` - The English name of the country
  * `country_code` - The ISO3166 code of the country
  * `phone`
* `shipping_lines` - An array of shipping rates
  * `id` - The Purple Dot ID of the shipping line
  * `price` - The unit cost of this shipping line, before taxes/discounts etc
  * `total`- The total cost of this shipping line, after tax/discounts etc are considered
  * `title` - The user-facing name of the shipping rate
  * `code` - The shipping rate carrier code
  * `tax_lines` - The taxes applied to the shipping rate
    * `price`  - The total amount of tax for the shipping line
    * `rate`  - The tax rate as a decimal
    * `title`  - The name of the tax
    * `inclusive`  - Whether this tax is already included in the shipping line price
* `note` - optional notes from the Shopify order

Examples:

{% code overflow="wrap" %}

```
curl --request GET \
     --url 'https://www.purpledotprice.com/admin/api/v1/fulfillment_order/a1b2c3d4-e5f6-7890-1234-567890abcdef' \
     --header 'X-Purple-Dot-Access-Token: <access_token>'
```

{% endcode %}


# /fulfillment

#### `POST /fulfillment`

#### Create a fulfillment for a fulfillment order.

Request:

* `fulfillment`
  * `fulfillment_order_id` (UUID) - Required. The ID of the Fulfillment Order you are fulfilling
  * `line_items` (array) - Optional. If left blank, all line items will be fulfilled
    * `id` (string) - Required. The Purple Dot ID of the line item
    * `quantity`(number) - Required. The quantity of that line item that are being fulfilled
  * `notify_customer` (boolean) - Optional. Whether the customer is notified. If `true`, then a notification is sent when the fulfillment is created. The default value is `false`
  * `tracking_info` - Optional.
    * `number` (string) - The tracking number of the fulfillment
    * `url` (string) - The URL to track the fulfillment

Example payload:

```
{
  "fulfillment": {
    "fulfillment_order_id": "00000000-00000000-00000000-00000000",
    "line_items": [
      {
        "id": "00000000-00000000-00000000-00000000",
        "quantity": 5
      }
    ],
    "notify_customer": true,
    "tracking_info": {
      "number": "1234567890",
      "url": "https://www.myshipping.com/track/?tracknumbers=1234567890"
    }
  }
}
```


# /refund

#### `POST /refund`

#### Create a refund for an order.

Refunds money to the shopper against the underlying Purple Dot preorder payments. You must provide either a **line-item refund** (only supported for Shopify stores) or an **custom amount refund**, but not both.

**Request Body**:

* `id` (string) - Required. Idempotency key.&#x20;
  * Must be unique for each distinct refund. This could be a refund document number, return ID, or support case/ticket ID tied to that specific refund.
  * Reuse the **same** `id`, `order`, and payload when retrying after a timeout or network error. A successful prior attempt returns the same result and will not refund the shopper twice. Sending a different payload for the same `id` and `order` returns 409 Conflict.
  * Use a **new** `id` for each separate refund, even on the same order.
  * Do **not** generate a new random ID on every HTTP retry.
* `order` (string) - Required. External order ID to refund.
  * On Shopify stores, use the **Shopify order ID**.&#x20;
  * For other e-commerce platforms, use the Purple Dot **fulfillment order UUID**. Look up the fulfillment order via [`GET /fulfillment-orders`](https://docs.getpurpledot.com/docs/purple-dot-apis/private-api/fulfillment-orders).

For a **line-item refund**, provide at least one of:

* `line_items` (array) - Optional. The line items to refund. Each element must have:
  * `id` (string) - Required. External line item ID (e.g. Shopify line item ID).
  * `quantity` (number) - Required. Must be 1.
* `shipping` (boolean) - Optional. Refund shipping for the order. Shipping can only be refunded once per order.

{% hint style="info" %}
Note: line-item refunds are currently only supported for Shopify stores.
{% endhint %}

For a **custom amount** **refund**, provide:

* `amount` (string) - Required. The amount to refund (must be a decimal string).
* `currency` (string) - Required. Must match the order's presentment currency.

**Response Data**:

* `id` - The idempotency key from the request
* `order` - The external order ID from the request
* `refunded`
  * `amount` - The refunded amount as a string
  * `currency` - The refunded amount currency

**Errors**:

* `400` - `INVALID_REFUND_REQUEST`: Mixed line-item and appeasement payload; missing or invalid amount/currency for appeasement; or currency does not match the order.
* `400` - `INVALID_LINE_ITEMS`: The line items array contains invalid entries (e.g. missing id or quantity, or quantity is not 1).
* `400` - `CURRENCY_MISMATCH`: Appeasement refund currency does not match the order's presentment currency.
* `400` - `SHIPPING_ALREADY_REFUNDED`: Line-item refund with shipping requested but shipping was already refunded for this order.
* `400` - `NOT_ENOUGH_ITEMS_LEFT_TO_REFUND`: Requested line-item quantities exceed the remaining refundable quantity.
* `404` - `UNKNOWN_ORDER`: Order not found or not for this store.
* `404` - `UNKNOWN_LINE_ITEMS`: One or more line item ids are not on the order.
* `409` - `IDEMPOTENT_REQUEST_PAYLOAD_MISMATCH`: Same id and order were used with a different payload.
* `500` - REFUND\_FAILED: Order has mixed checkout/preorder line items, or the payment refund failed.
* `501` - Orders that span multiple pre-orders are not supported.

**Examples**:

{% code overflow="wrap" %}

```bash
curl --request POST \
     --url 'https://www.purpledotprice.com/admin/api/v1/refund' \
     --header 'Content-Type: application/json' \
     --header 'X-Purple-Dot-Access-Token: <access_token>' \
     --data '{"id": "refund-001", "order": "gid://shopify/Order/123", "line_items": [{"id": "gid://shopify/LineItem/456", "quantity": 1}], "shipping": false}'
```

{% endcode %}

{% code overflow="wrap" %}

```bash
curl --request POST \
     --url 'https://www.purpledotprice.com/admin/api/v1/refund' \
     --header 'Content-Type: application/json' \
     --header 'X-Purple-Dot-Access-Token: <access_token>' \
     --data '{"id": "refund-002", "order": "gid://shopify/Order/123", "amount": "10.00", "currency": "USD"}'
```

{% endcode %}

{% code overflow="wrap" %}

```json
{
  "meta": {
    "result": "success"
  },
  "data": {
    "id": "refund-001",
    "order": "gid://shopify/Order/123",
    "refunded": {
      "amount": "42.00",
      "currency": "USD"
    }
  }
}
```

{% endcode %}


