> For the complete documentation index, see [llms.txt](https://docs.enable3.io/enable3/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.enable3.io/enable3/tech/integration/shopify.md).

# Shopify

This guide covers how the Enable3 widget is embedded into a Shopify storefront, and how Shopify order activity and revenue can optionally be synced into Enable3 to power Missions, Rewards, and analytics. For the merchant-facing overview, see the [Shopify page](/enable3/getting-started/basic-setup/shopify-loyalty-app.md).

The integration doesn't require any changes to Enable3's existing Integration API or Proxy API. The core requirement is a server-side layer — a Shopify App Proxy, or a backend owned by the merchant/app — that securely holds the `X-API-KEY` and maps `operatorUserId` to the `Shopify customer.id`.

### User Identification

Enable3 identifies users via **operatorUserId** (string), created or found through the Integration API. For Shopify, the natural mapping is the **Shopify Customer ID**:

`operatorUserId = customer.id (Liquid)`

For **guests** (no customer.id), an anonymous widget URL can be issued instead. Guests can still link Telegram, X, or a wallet inside the widget if the merchant has enabled it — that identity attaches to the Enable3 user created for the anonymous session.

### APIs Used

#### Integration API (OperatorIntegrationController)

Authenticated via `X-API-KEY` header — server-side only. Used for user creation/lookup and widget token issuance.

`GET /api/v1/integration/user/{operatorUserId}/widget?language=...` — returns WidgetUrlDto.url, the full widget URL with token. This is the primary endpoint for storefront embedding.

`GET /api/v1/integration/user/{operatorUserId}/token?language=...` — returns AuthResponseDto.token (token-only alternative).

#### Proxy API (ProxyController)

Used to push Shopify activity into Enable3.

POST /v1/event — AppEventDto: operatorUserId, eventId, value, createdAt (optionally tags)

POST /v1/revenue — RevenueDto: requestId, revenue, date

Segments are also supported via the Proxy API where applicable.

#### Widget Auth Options (JWT-authenticated, called from the widget)

`GET /api/v1/user/widget-auth-options` — returns `WidgetAuthOptionsDto`, showing which login/link options the merchant has enabled for visitors: Telegram, Twitter/X, WalletConnect, MetaMask, Coinbase Wallet, Trust Wallet, Rabby Wallet.

Each option is gated by its own feature flag (TELEGRAM\_AUTHENTICATION, TWITTER\_AUTHENTICATION, WALLET\_AUTHENTICATION) and is **configured in Enable3**, not in Shopify. Linking one of these identities attaches it to the already-created user for that `operatorUserId` — so a single Shopify customer can accumulate additional linked identities without changing their Missions/Rewards progress.

{% hint style="warning" %}
Important: The Enable3 API key must never be exposed on the storefront. Widget URL/token issuance must always happen through a server layer — never directly from theme/Liquid code.
{% endhint %}

### Recommended Architecture

* Shopify App + App Proxy + Theme App Extension is the recommended default for a scalable, secure merchant experience.
* Shopify App (backend) — resolves the shop to its stored Enable3 API key and calls the Integration API
* App Proxy — routes storefront-to-backend calls without exposing the API key
* Theme App Extension — renders the widget via an app block/embed

**Flow**: the storefront calls the App Proxy endpoint with customer\_id sourced from Liquid, the backend resolves the shop's Enable3 API key, calls the Integration API for a widget URL, and returns an iframe-ready URL (or embeddable HTML) to the storefront.

Logged-in customer: `operatorUserId = customer.id`

Guest: empty or a temporary ID, per the backend's guest strategy

{% hint style="info" %}
A manual, no-app fallback (merchant-issued backend endpoint, or an anonymous domain-bound widget) is technically feasible but should be treated as a constrained, explicitly-supported path rather than a default — it carries more setup and support overhead than the App + App Proxy approach.
{% endhint %}

#### Event and Revenue Sync (Optional Add-on)

To credit purchases and actions in Enable3, Shopify data is sent to the Proxy API — typically via Shopify Webhooks (orders/paid, orders/create).

A backend or serverless handler receives the webhook, verifies its signature, resolves the shop's Enable3 API key, maps the order to operatorUserId and revenue, then calls:

POST /v1/event for the business event (e.g. order paid)

POST /v1/revenue for revenue tracking

### Mapping basics:

* `operatorUserId = order.customer.id` (when available)
* `revenue = order total`, following a defined currency/tax/shipping policy
* requestId should be idempotent and stable (e.g. shop + order id + event type)
* date/createdAt should be normalized to UTC

{% hint style="warning" %}
Shopify webhooks can be delayed or delivered more than once. Use a stable, idempotent requestId and process the event + revenue pair as a single workflow to avoid partial ingestion (an event with no matching revenue, or vice versa).
{% endhint %}

{% hint style="warning" %}
Important: Shopify revenue can be multi-currency and may include or exclude tax, shipping, or discounts. Define a clear revenue policy (gross vs. net, shipping in/out) up front, and handle refunds via compensating events/revenue adjustments — inconsistent rules here will break Missions and analytics downstream.
{% endhint %}
