Alpha testing: all current functionality is free while VAT Engine is in active development

Shopify

Shopify integration guide for VAT Engine, covering verified shop identity, account linking, source mapping, fulfillment routing, protected-data posture, special-product review signals, imported-goods and IOSS review signals, and the current order preview and import workflow.

Overview

Use this page if you want to connect a Shopify store to VAT Engine.

It is written for merchants, agencies, and developers who are setting up a customer account connection. Internal deployment flags, support runbooks, and backend-only implementation details are kept in VAT Engine's internal MD/ notes instead of this public guide.

Shopify setup now starts from Dashboard -> Integrations using VAT Engine's guided OAuth connection flow. VAT Engine redirects you to Shopify for approval, stores the resulting token and granted scopes server-side, and brings you back to the dashboard when the install finishes.

What The Shopify Connection Does

  • Connects one Shopify store to one VAT Engine customer account
  • Stores the Shopify credentials needed for future sync and webhook handling
  • Registers the required operational Shopify webhook topics for that specific store after install or reconnect
  • Minimizes retained Shopify webhook data and refetches the authoritative order snapshot before VAT Engine imports filing-relevant changes
  • Lets you map the store to a VAT Engine source profile for reporting
  • Automatically reuses the connected store mapping and matching source aliases when imported Shopify activity should land under a specific VAT Engine source profile
  • Lets account operators preview one Shopify order and its normalized VAT Engine events before running an import
  • Prepares the account for imported order activity and review workflows

App Configuration Ownership

VAT Engine now separates app-level Shopify configuration from per-store connection data.

  • Per-store rows in Dashboard -> Integrations own the verified Shopify shop identity, source mapping, connection status, and whether VAT Engine holds tokens for that specific store.
  • The read-only Shopify app configuration panel on the same page shows the shared app URL, OAuth callback URL, privacy webhook URL, requested scopes, and pinned Shopify API versions used by every Shopify install on that VAT Engine deployment.

If the requested scopes, callback URL, or API versions need to change, update the deployment-owned Shopify app configuration first and then reconnect the affected store. Do not expect those values to be edited store by store inside VAT Engine.

Data Minimization And Approval Posture

VAT Engine's current Shopify connector is intentionally narrow.

  • The deployment-level install scope policy allows read_orders, read_products, read_merchant_managed_fulfillment_orders, read_third_party_fulfillment_orders, and, when older-history access is needed, read_all_orders.
  • Shopify order fetches are limited to order, refund, duty and additional-fee, tax, channel, country-code, and product-tax-mapping evidence such as product or variant IDs, SKU, tags, category, app-owned product metafields, Shopify's gift-card flag, and line-level taxability signals.
  • VAT Engine also reads Shopify's low-sensitivity order-level taxExempt flag and purchasing entity type so it can resolve B2B/B2C status without reaching into customer-contact fields or street-level addresses.
  • Large Shopify product tags or app-owned product-metafield payloads are reduced to bounded matcher-safe signals before VAT Engine stores canonical evidence, so unusually large catalog metadata degrades to reviewable truncation instead of breaking imports.
  • Customer contact fields and street-level address fields are not part of the current VAT Engine Shopify order adapter.

Shopify's app-review model expects apps to request only the minimum data they actually need. If VAT Engine ever needs broader Shopify customer data in the future, that should be treated as a new explicit app-policy change rather than a per-store toggle.

Before You Start

Have these ready:

  1. A VAT Engine customer account with dashboard access
  2. Admin access to the Shopify store
  3. The store's permanent myshopify.com domain, for example your-store.myshopify.com
  4. Optional but recommended: the VAT Engine source profile that should represent this store
  5. Optional: your preferred display label for the store inside VAT Engine

Shopify's official documentation treats the permanent .myshopify.com domain as the stable shop identifier for app configuration and embedded app context. Use that value in VAT Engine rather than a storefront custom domain or an /admin URL.

Current Dashboard Flow

  1. Sign in to the VAT Engine customer account that should own the Shopify store connection.
  2. Open Dashboard -> Integrations.
  3. Optional but recommended: create a matching Source profile first if you want reporting grouped under a stable store label.
  4. Create a new Shopify integration in VAT Engine.
  5. Enter the store's permanent your-store.myshopify.com domain and optional display label.
  6. Click Connect Shopify.
  7. Review and approve the requested scopes in Shopify.
  8. Wait for VAT Engine to return you to Dashboard -> Integrations.
  9. Confirm the integration status looks correct and that the source profile mapping is what you expected.

Order Preview And Controlled Import

After the Shopify connection is in place, open the integration's Activity page in VAT Engine.

  • Use Shopify order adapter preview to enter either a Shopify numeric order ID or a full Shopify order GID.
  • VAT Engine fetches that order through Shopify Admin GraphQL and shows the normalized sale/refund events it would import.
  • The preview now also shows the country-evidence policy and customer-type resolution path for each normalized event. Physical goods and shipping-charge rows use shipping country first with billing fallback, while non-shipping supplies use billing country first with shipping fallback. If Shopify reports taxExempt=true without a purchasing-company identity, VAT Engine keeps that row in review instead of forcing B2B or B2C.
  • The same preview now also distinguishes cash-settled refunds from credit-note-only corrections by using Shopify refund transaction outcomes, shows Shopify order adjustments as separate correction rows, and surfaces the original sale reference when Shopify provides a stable order-line link.
  • Shipping-charge, refunded-shipping, and shipping-linked adjustment rows stay separate from goods rows. VAT Engine auto-classifies those rows only when Shopify's observed shipping VAT and the actual shipping VAT amount both match the destination country's standard VAT rate; zero-rate, reduced-rate, exempt, amount-mismatched, or otherwise non-standard shipping tax stays in review with an explicit shipping allocation diagnostic.
  • The same preview now also shows marketplace or merchant liability for each normalized event when Shopify exposes a decisive signal. VAT Engine prefers Shopify tax-line liability, uses the mapped source-profile default only as a fallback policy, and keeps marketplace-channel orders in review when Shopify does not expose enough liability evidence to file confidently.
  • The same preview now also shows imported-goods and IOSS diagnostics. When Shopify exposes non-EU dispatch evidence together with duties or import-fee signals, VAT Engine flags the affected normalized event as an imported-goods candidate, records the detected import origin, and keeps the row in review unless it can derive a filing-safe consignment intrinsic value. VAT Engine does not treat shipping, duties, or additional fees as part of the intrinsic goods value, and it no longer lets those imported-goods signals silently override an explicit non-goods Shopify product tax mapping such as service or tbe_service.
  • VAT Engine now also uses Shopify's own special-product signals before it trusts a catalog rule too far. Gift-card products with no VAT are excluded automatically, while taxed gift cards, non-taxable rows without a matching exempt rule, and zero-VAT rows without the right zero-rate or exempt mapping stay in review with explicit product-mapping diagnostics.
  • VAT Engine now also treats Shopify taxesIncluded as the amount-basis signal for each normalized event. When Shopify line prices already include VAT, VAT Engine backs VAT out before it evaluates the canonical taxable base. When Shopify keeps tax separate, VAT Engine uses the captured line amount as the taxable base and adds VAT on top for the gross amount.
  • For zero-VAT Shopify rows, VAT Engine now separates tax treatment more explicitly. Order-level taxExempt=true pushes the row toward exempt, an explicit zero-rate Shopify tax line pushes it toward zero-rated, and contradictory or incomplete evidence stays in review instead of silently treating every zero-VAT row as the same case.
  • The product-tax-mapping write path now enforces the same special-product policy end to end: excise/new-means/assembly flags are limited to goods or imported_goods mappings and cannot be combined with gift_card handling, and the imported-event review queue now shows those markers back to operators during manual review.
  • When Shopify exposes fulfillment-order routing for a physical-goods line, VAT Engine now also shows the dispatch-country topology for that line. One Shopify line can split into multiple VAT Engine events by dispatch-country group if Shopify reports multi-origin fulfillment.
  • Those split events now also keep fulfillment-location alias evidence scoped to their own dispatch segment, so a DE split row does not inherit NL warehouse aliases during source attribution.
  • Shopify shipping sale rows and refund-shipping rows now reuse fulfillment-location alias evidence only when Shopify routing points to one unambiguous assigned location for the order. If the order is routed across multiple locations, VAT Engine leaves shipping-family source attribution fail-closed instead of guessing from the whole warehouse set.
  • If Shopify later cancels an order that already had a committed sale imported, VAT Engine now shows any remaining cancellation residual explicitly instead of silently mutating the original sale row.
  • If one of those later non-sale corrections belongs to a VAT return period that is already locked or filed, VAT Engine keeps the closed period immutable. When the correction can be linked back to an already imported original sale, VAT Engine stores it on the first later open correction date and retains the original Shopify effective date in canonical evidence. If the original sale cannot be linked, VAT Engine blocks the import and asks for operator review instead of inventing a closed-period rewrite.
  • The same card can then run a controlled import for those normalized events.
  • If Shopify reports that the fetched order snapshot is partial or truncated, VAT Engine still shows the preview for diagnosis but blocks the import until a complete order fetch is available.

This is meant as an operator validation tool while the broader background sync path continues to ship. It is not a substitute for full automated historical sync, reconciliation, or final filing-ready classification review.

Automatic Source Attribution

VAT Engine now applies the same source-attribution rules to Shopify order preview/import and to the background sync workers.

  • If the Shopify integration is already linked to a VAT Engine source profile, that mapping stays the first choice.
  • If you maintain source aliases, VAT Engine can also match the verified Shopify store through its shop domain, Shopify shop ID, store/display label, supported Shopify channel labels, or fulfillment-location labels when Shopify exposes fulfillment-order routing for the order.
  • The order preview now shows which source profile match VAT Engine would use before import, so an operator can correct aliases or the integration mapping before filing-relevant data lands.
  • If Shopify omits or truncates that routing evidence, VAT Engine keeps the affected source or dispatch decision reviewable instead of guessing from a partial warehouse signal.

VAT Engine now also schedules periodic Shopify reconciliation in the background for eligible storefronts and still lets operators queue one manually from the same activity page when a faster recheck is needed.

For larger or older history, the same activity page now has a separate historical backfill control that uses Shopify Bulk Operations instead of deep normal pagination. That control is only available when the connected Shopify install has the approved read_all_orders scope, because Shopify limits older-order access otherwise. VAT Engine also validates the signed bulk-result destination and size automatically, so malformed or unexpectedly large upstream result files fail closed instead of importing partial data silently. Shopify Bulk Operations still impose their own query-shape limits, so app-owned product metafield matching is available on direct order preview/import and recent-window worker refetches, while bulk history backfill currently relies on product, variant, SKU, tag, and category signals only.

Currency And Presentment

Shopify can store the same order amounts in two currency views: the store's shop currency and the customer's presentment currency. VAT Engine imports the shop-currency amounts as the canonical VAT ledger amounts because those are the stable values Shopify exposes for reconciliation across order, refund, shipping, duty, fee, and adjustment records.

If a customer paid in another presentment currency, VAT Engine keeps that presentment currency and amount evidence in the Shopify order preview so operators can explain the storefront/customer view. It does not replace the canonical shop-currency amount used for VAT classification. Normal filing currency conversion still happens later in VAT Engine's reporting layer.

The same activity page now also shows a Historical coverage status for the store. Use that area to confirm whether the store is still limited to Shopify's default recent 60-day order window, has the approved read_all_orders scope but still needs a first historical backfill, already has queued or running historical work, or has completed a historical backfill successfully. That keeps the older-history boundary explicit for operators without marking every normal read_orders-only install as generically unhealthy.

Historical bulk backfill also fails closed when Shopify's bulk snapshot is incomplete for filing-relevant correction data. If refund transactions or refund order adjustments were truncated in the bulk result, VAT Engine now blocks that order import instead of guessing whether the correction was a settled refund, a credit note, or an incomplete discrepancy adjustment.

The same activity page now also exposes a Shopify Admin API throttle panel. That panel shows the last observed GraphQL cost snapshot, current bucket availability, restore rate, recent wait time, and whether VAT Engine has throttled itself for that store recently. Use it as operator telemetry only: VAT Engine already applies the shared same-store pacing automatically on the backend. Some deployments can suppress that live panel when the same Shopify shop is linked in more than one VAT Engine account, because the throttle bucket is shared at the Shopify app+store level.

The activity page also shows a Shopify webhook subscriptions block. VAT Engine uses Shopify's shop-scoped Admin API webhook subscriptions for operational order/refund/uninstall topics, verifies that they still point at the current receiver URL, requests only the stable identifier fields VAT Engine needs for supported operational topics, and offers a repair action if Shopify lost authorization or still has a stale receiver URL from an older setup. If Shopify rejects a repair or reconnect attempt, the activity page now shows Shopify's returned reason directly instead of a generic webhook-registration failure. If Shopify says it cannot create the specified topic, review the app's API access requests in Partner Dashboard before retrying.

Guided App Or Plugin Flow

When the guided Shopify app or plugin is released, the intended merchant flow is:

  1. Install the VAT Engine app in Shopify.
  2. Sign in to the correct VAT Engine customer account during setup.
  3. Choose which VAT Engine source profile should represent the store.
  4. Approve the requested Shopify scopes.
  5. Finish setup and let VAT Engine complete the account link automatically.

If you manage multiple client accounts, do not connect a client store while signed in to your own personal or another customer's VAT Engine account. The integration should be created inside the account that owns that store's reporting data.

Field Mapping

VAT Engine fieldWhat to enterNotes
PlatformShopifySelect Shopify for a normal Shopify store connection.
Source profileOptional existing VAT Engine source profileRecommended if you already use store-level reporting in VAT Engine.
Display nameOptional internal label, for example Main EU StoreLeave blank to use the verified Shopify shop domain as the default.
Shop domain or base URLyour-store.myshopify.comUse the permanent Shopify domain, not a custom storefront domain.
External shop IDManaged automaticallyVAT Engine records the verified Shopify shop ID after install.
Granted scopesManaged automaticallyVAT Engine records granted scopes from Shopify's callback.
StatusUsually connected after installExisting integrations can still be marked action_required or disconnected if follow-up is needed.
Access tokenManaged automaticallyVAT Engine stores the OAuth token server-side; it is not shown back in the browser.
Refresh tokenManaged automatically when Shopify returns oneMost installs will not require you to enter this manually.

How To Get The Right Shopify Values

Store Domain

Use the store's permanent Shopify domain:

  • your-store.myshopify.com

Do not use:

  • a storefront custom domain
  • a staff login email
  • a contact email
  • an /admin URL

Access Token And Granted Scopes

Shopify Admin API requests require a valid access token, but VAT Engine now obtains and stores that token from the OAuth install flow for you.

For VAT Engine:

  • start the connection from Dashboard -> Integrations
  • approve the requested scopes in Shopify
  • let VAT Engine capture the resulting token and scope grant from Shopify's callback

Do not paste storefront passwords, user passwords, or webhook topics into Shopify connection fields. If an older manual integration needs updated credentials, use Reconnect Shopify in the edit dialog instead of editing token values directly.

External Shop ID

VAT Engine records the verified Shopify shop ID automatically from the connected install. If you reconnect an older manual Shopify integration and VAT Engine rejects the submitted shop identity, use the shop.id and shop.myshopifyDomain returned by Shopify as the source of truth.

Webhook Expectations

After Shopify returns to VAT Engine successfully, open the integration activity panel and use the webhook URLs shown by VAT Engine.

  • Operational Shopify webhooks such as order, refund, or uninstall events use the per-integration VAT Engine receiver URL shown after the integration is saved.
  • For supported operational topics, VAT Engine treats Shopify webhooks as invalidation signals. It keeps only the minimal identifiers needed for replay and then refetches the authoritative order or uninstall state through Shopify before it applies any filing-relevant change. If VAT Engine cannot reduce a verified operational payload to that minimal identifier set safely, it records metadata only and does not queue replay from the raw body.
  • VAT Engine currently automates background processing for supported operational topics such as orders/create, orders/updated, orders/cancelled, orders/edited, orders/paid, orders/fulfilled, orders/partially_fulfilled, refunds/create, and app/uninstalled. Other verified operational topics are still recorded for audit visibility, but they are not reprocessed automatically yet.
  • VAT Engine also runs a periodic reconciliation pass against recently updated Shopify orders so a delayed or missed webhook does not have to be the only path that refreshes VAT Engine data.
  • Mandatory Shopify privacy topics such as customers/data_request, customers/redact, and shop/redact use a separate static VAT Engine privacy endpoint instead of the per-integration receiver URL.
  • VAT Engine also runs a background privacy-review worker for those mandatory Shopify privacy topics. customers/redact requests auto-complete when no exact retained imported evidence matches the provided Shopify order IDs and switch to legal-retention state when retained filing evidence still exists. customers/data_request requests auto-complete only when no exact retained filing evidence matches the provided Shopify order IDs; requests with retained evidence still require operator export to the store owner within Shopify's 30-day window. shop/redact still requires operator cleanup for remaining shop-scoped metadata after VAT Engine removes stored secrets and purges retained privacy payloads.
  • VAT Engine expects the payload to match the exact Shopify compliance topic: customers/data_request must include customer plus data-request metadata, customers/redact must include customer plus orders_to_redact, and shop/redact must carry only shop-level erase metadata. Replaying one topic while changing only headers to another topic is rejected.
  • VAT Engine also binds Shopify's documented shop_id and shop_domain identifiers together when it routes privacy callbacks, so the same shop domain shown in Shopify must match both the webhook headers and the privacy payload for the request to be accepted.

If you are waiting for the guided app or plugin release, VAT Engine should eventually automate these registrations during install. Until then, do not assume that one webhook URL covers every Shopify topic.

Shopify's official webhook guidance also requires a public HTTPS endpoint for live deliveries, so a plain localhost URL is not enough for real Shopify webhook traffic.

If Shopify sends app/uninstalled, VAT Engine now disconnects that storefront automatically and revokes the stored Shopify access credentials after the background webhook job finishes.

Common Mistakes

  • Connecting the store while signed in to the wrong VAT Engine customer account
  • Using a custom storefront domain instead of your-store.myshopify.com
  • Pasting a staff email or store contact email into the shop-domain fields
  • Trying to paste legacy manual credentials into a new Shopify OAuth connection
  • Treating webhook topics such as orders/create as OAuth scopes
  • Pointing live Shopify webhooks at localhost instead of a public HTTPS URL
  • Using the privacy endpoint for order or refund webhooks