> ## Documentation Index
> Fetch the complete documentation index at: https://docs.etho.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Shopify

> Connect a Shopify custom app and ground Olympus offers in your live catalog

Shopify connects your store catalog to Olympus. Products, variants, prices, availability, images,
and storefront links remain managed in Shopify. In Olympus, you choose which of those products back
an Offer before using them in ads, copy, or funnels.

<Note>
  Shopify is in pilot activation. If the card says **Coming soon**, your
  workspace has not been enabled yet. The setup below applies after an Olympus
  administrator enables the integration.
</Note>

## Before you start

You need:

* Owner or Admin access in Olympus.
* Permission to create and configure a custom app for the Shopify store.
* The store's permanent `your-store.myshopify.com` domain.

Olympus asks for the app's client ID and client secret in the protected connection dialog. Never
send either credential through Agent chat, email, or support messages.

## Create the custom app

<Steps>
  <Step title="Open the Shopify Dev Dashboard">
    Create an app for the store from the [Shopify Dev Dashboard](https://dev.shopify.com/dashboard).
    Keep the dashboard open while you finish the Olympus connection.
  </Step>

  <Step title="Set the redirect URL">
    Add the OAuth callback shown by your Olympus environment:

    ```text theme={null}
    https://<your-app-domain>/api/integrations/shopify/callback
    ```

    The URL must match exactly, including the `https` scheme and path.
  </Step>

  <Step title="Grant read access">
    Start with `read_products`. Commerce sync also needs `read_orders`, `read_customers`,
    `read_inventory`, `read_returns`, and `read_marketing_events`. Stores that approve
    `read_all_orders` can backfill more than Shopify's ordinary 60-day order window. Olympus never
    requests Shopify write access.
  </Step>

  <Step title="Enter the store credentials in Olympus">
    In **Settings > Integrations > Commerce**, open Shopify. Enter the permanent store domain,
    client ID, and client secret, then choose **Prepare connection**. Olympus encrypts the
    credentials and shows the three privacy webhook URLs for this connection.
  </Step>

  <Step title="Add the privacy webhooks">
    Copy the generated URL into each required compliance topic in Shopify:

    * Customer data request: `customers/data_request`
    * Customer data erasure: `customers/redact`
    * Shop data erasure: `shop/redact`

    Each topic uses the same connection-specific URL. Do not replace it with a generic webhook URL.
  </Step>

  <Step title="Approve access in Shopify">
    Choose **Continue to Shopify**, review the requested read-only scope, and approve the app. The
    first catalog import starts in the background after OAuth completes.
  </Step>
</Steps>

## Work with imported products

Open **Offers > Products** to see Shopify source badges and current sync state. Select one or more
Shopify products and choose **Use in offer**. Olympus can create a draft or add the products to an
existing Offer with catalog-grounded pricing, delivery, and line items; you still write or approve
the promise and positioning.

Fields supplied by Shopify are locked in Olympus. Change those values in Shopify, then choose
**Refresh Shopify** from the Products page. User-authored Offer copy is never overwritten by sync.

## Check status and refresh

The integration status reports connection state, granted scope names, API version, the last accepted
webhook time, import progress, and safe issue aggregates. It never exposes the app secret, access
token, OAuth code, webhook HMAC, customer identifiers, or raw webhook payloads.

Catalog reads and status are also available to bearer-authenticated MCP clients. Catalog refresh and
product-to-Offer mapping remain approval-gated inside Olympus.

## Commerce reporting

After commerce scopes are approved, Olympus syncs customers before orders, then keeps paid orders,
edits, cancellations, and refunds current through signed webhooks. Purchases appear on Connect
contacts, while **Measure > Store** shows net revenue, AOV, repeat rate, customer LTV, cohorts,
blended ROAS, MER, and channel attribution. The Store page and Agent/MCP commerce reads return
aggregates only; they do not return customer rows, names, emails, phone numbers, addresses, raw
journeys, or webhook payloads.

The first backfill covers 60 days unless Shopify grants `read_all_orders`. Backfill is safe to resume
after an interruption, and a newer webhook observation wins over an older bulk snapshot.

<Note>
  Shopify revenue can be sent to Meta Conversions API only after an administrator enables the
  setting, records consent, and chooses a connected default pixel. The setting is off by default.
</Note>

### Reporting limits

* Store revenue is net of recorded refunds. It is not a profit report.
* Cost of goods is reported as unavailable until Shopify inventory costs are synced; Olympus does
  not invent margin.
* Revenue attribution uses last touch. Cohorts and acquisition-channel LTV use first touch.
* Without an `oly_link` or a unique UTM match, revenue remains in an unmatched or direct bucket.
* Orders without a resolvable customer identity contribute to revenue totals but not customer LTV
  or repeat-rate denominators.

## Disconnect

Disconnecting stops new catalog imports and webhook processing. Imported products remain in Olympus
as detached records so existing Offers and historical work do not break. Reconnect the same store to
reattach those product identities and resume updates.

<Warning>
  Disconnect the app in Olympus before deleting it in Shopify when possible. If
  Shopify uninstalls the app first, Olympus verifies the token failure and then
  marks the local connection disconnected.
</Warning>

## Troubleshooting

* **OAuth returns to the wrong page:** Check that the redirect URL matches the callback above exactly.
* **The store domain is rejected:** Use the permanent lowercase `.myshopify.com` domain, not a custom storefront domain.
* **Products do not appear:** Confirm `read_products` is granted, then start a refresh from the Products page.
* **A product cannot be edited:** Shopify-sourced fields are intentionally read-only. Edit the product in Shopify and refresh.
* **The integration is degraded:** Test the connection from Settings. A rejected token requires reconnecting the app.

## Pilot activation checklist

Shopify stays locked until every item below is observed on the pilot store. Automated tests do not
replace these provider and account observations.

* [ ] Complete OAuth with the real custom app and confirm the returned store matches the requested
  permanent `.myshopify.com` domain.
* [ ] Confirm imported product and variant counts match Shopify Admin.
* [ ] Process one test purchase and verify one contact, one Store opportunity, one purchase, one
  Meta Purchase delivery, and the expected Measure fact row.
* [ ] Refund that purchase and verify one immutable revision reduces net revenue without creating a
  duplicate purchase or conversion.
* [ ] Reject a delivery with a tampered HMAC and accept a replayed delivery only once.
* [ ] Send Shopify Dev Dashboard test deliveries for `customers/data_request`,
  `customers/redact`, and `shop/redact`; verify each reaches its terminal handled state.
* [ ] Run a customer-redact drill and confirm customer identity and raw match data are removed while
  deidentified purchase totals stay unchanged.
* [ ] Compare a hand-calculated Shopify customer cohort with **Measure > Store**.
* [ ] Run all Shopify SQL contracts against a reset local database.
* [ ] Review the status response and logs for credentials, raw payloads, customer identifiers, and
  personal data; none may appear.

### Activation evidence

| Evidence                        | State         | Observed at | Notes                                    |
| ------------------------------- | ------------- | ----------- | ---------------------------------------- |
| OAuth and granted scopes        | Pending pilot | —           | Requires the Shop Playbook custom app    |
| Catalog parity                  | Pending pilot | —           | Compare Shopify Admin and Olympus counts |
| Purchase and refund projection  | Pending pilot | —           | Verify Connect purchase and revision     |
| Meta Purchase delivery          | Pending pilot | —           | Verify in Meta Events Manager            |
| Measure facts and cohort parity | Pending pilot | —           | Compare with a hand-calculated sample    |
| Signed and compliance webhooks  | Pending pilot | —           | Requires public callback delivery        |
| Customer erasure drill          | Pending pilot | —           | Preserve deidentified financial totals   |

Do not set the activation evidence date or unlock the catalog until every row records an observed
result. The current evidence date is intentionally unset.

For Shopify's platform details, see [authentication and access tokens](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens), [Admin API scopes](https://shopify.dev/docs/api/usage/access-scopes), and [webhook subscriptions](https://shopify.dev/docs/apps/build/webhooks/subscribe).
