Shopify Integration Architecture - How ERPClaw Connects to Shopify
Technical architecture of the ERPClaw Shopify connector. Cloudflare Pages + Worker + your ERPClaw. Merchant data never transits our servers. Three latency tiers for command delivery.
This page explains what runs where, which boundary each piece of data crosses, and why the design puts merchant business data on the merchant’s own machine instead of on our infrastructure.
Three components
The connector has three moving parts and nothing else.
- Cloudflare Pages at
admin.shopify.erpclaw.ai. Serves the embedded admin UI (Polaris plus App Bridge v4). Loaded inside an iframe by Shopify Admin. - Cloudflare Worker at
shopify.erpclaw.ai. A small Hono app that handles the OAuth handshake, hands out pairing codes, receives status pushes, verifies GDPR webhooks, and delivers queued commands. - Your ERPClaw. Runs on a machine you control. Owns the merchant business data: orders, customers, products, GL entries, inventory. Talks to the Shopify Admin API directly using an OAuth token stored locally.
Shopify Admin (iframe)
|
v
Cloudflare Pages <----UI assets----
admin.shopify.erpclaw.ai
|
| App Bridge JWT
v
Cloudflare Worker <---OAuth, webhooks, status, commands---
shopify.erpclaw.ai
|
| pairing code redemption (one time)
| status push (every 15 min)
v
Your ERPClaw <===Shopify Admin API 2026-04===> Shopify
(SQLite on your machine) direct connection
The critical invariant: merchant business data (orders, customers, products) never transits the Worker. It flows on the bottom arrow, directly between your ERPClaw and Shopify.
Data flow during install (OAuth)
- Merchant clicks Add app in the Shopify App Store.
- Shopify redirects to
shopify.erpclaw.ai/oauth/install?shop=<shop>.myshopify.com. The Worker validates the shop domain against a strict regex, sets a__Host-prefixed state cookie, and redirects to Shopify’s OAuth consent screen. - Merchant approves. Shopify posts back to
/oauth/callbackwith an authorization code and the state. - The Worker verifies the state HMAC, exchanges the code for an offline access token, and stores it in Cloudflare KV under
pair:{code}with a ten-minute TTL. Alongside the token it stores a per-shop HMAC secret derived viaHKDF-SHA256(master, salt=shop, info="erpclaw-status-v1", L=32). - The admin UI loads and shows the six-character pairing code.
- Merchant runs
erpclaw shopify-connect --pairing-code <code>locally. ERPClaw callsGET /pair/<code>. The Worker returns the OAuth token and the per-shop HMAC secret, then synchronously deletes the KV entry. The code is single-use. - From this point ERPClaw holds the token. It calls
api.shopify.com/admin/api/2026-04/graphql.jsondirectly.
If the ten-minute window lapses, the code is gone and the merchant generates a fresh one.
Data flow during steady state
Your ERPClaw pulls Shopify data on its own schedule using its local OAuth token. The Worker is out of the data path.
Every 15 minutes your ERPClaw POSTs a small status blob to
shopify.erpclaw.ai/status/<shop>. The blob contains:
- ERPClaw version string
- Timestamp of last successful sync
- Count of orders synced in the last 24 hours
- Count of GL entries posted in the last 24 hours
- Integer error count
- Local URL for the Open ERPClaw button
The push is signed with the per-shop HMAC and a timestamp (±300 second
tolerance). The Worker verifies it, writes it to KV under
status:{shop}, and uses it to render the admin UI status card. No
customer content, no order content, no financial amounts.
Three latency tiers for command delivery
The admin UI can queue commands (Sync now, Disconnect). The Worker delivers them to your ERPClaw in one of three ways:
Active tier (SSE): if your ERPClaw is online and holds an open
EventSource to /events/<shop>, the Worker pushes commands
immediately. Latency: a few hundred milliseconds.
Scheduled tier (15-minute push): when ERPClaw posts its next status blob, the Worker piggybacks any queued commands in the response body. Latency: up to 15 minutes. This is the default.
On-demand tier: the CLI command erpclaw shopify-flush-pending-events
forces an immediate round trip. Useful from scripts or cron jobs.
All three tiers use the same command schema and the same
acknowledgement mechanism. Delivery is at-least-once; commands carry
an ack_id for deduplication.
GDPR webhooks
Shopify requires four compliance webhooks. All four hit the Worker.
The Worker verifies the X-Shopify-Hmac-Sha256 signature
(constant-time compare against SHOPIFY_CLIENT_SECRET) before any
processing.
customers/data_request: Worker holds no customer data; queues agdpr-dispatchcommand for your ERPClaw.customers/redact: same path; your ERPClaw handles the actual redaction.shop/redact: fired 48 hours after uninstall. Worker deletes all*:{shop}KV keys. ERPClaw preserves GL entries (immutable; covered by GDPR Article 17(3)(b) exception for tax and accounting).app/uninstalled: Worker drops KV state immediately.
Data location summary
| Data | Where it lives | Retention |
|---|---|---|
| Shop domain, shop owner email | Cloudflare KV (meta:{shop}) | Until uninstall + 30 days |
| OAuth access token | Cloudflare KV (pair:{code}) during handoff only | 10 min max, deleted on redemption |
| Per-shop HMAC secret | KV during handoff, then held by your ERPClaw | 10 min on Worker, indefinite on your ERPClaw |
| Status blob | Cloudflare KV (status:{shop}) | 30-day rolling |
| Orders, customers, products | Your ERPClaw SQLite database | Indefinite; you control it |
| GL entries | Your ERPClaw SQLite database | Indefinite; immutable |
| Worker access logs | Cloudflare Logpush to R2 | 90 days |
Source of truth
- Shopify connector code: github.com/avansaber/erpclaw-addons
- Privacy policy: avansaber.com/privacy-shopify
- Shopify Admin API version pinned:
2026-04