Shopify
Technical reference for engineers or technical partners building the Shopify integration
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.
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.
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.
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
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.
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 policyrequestId should be idempotent and stable (e.g. shop + order id + event type)
date/createdAt should be normalized to UTC
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).
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.
Last updated