More Shopify documentation
Shopify Integration Architecture in ERPClaw
Technical architecture of the ERPClaw Shopify connector: Cloudflare Pages plus Worker plus your ERPClaw. Orders and customer records sync directly, not via our servers.
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 or PostgreSQL on your machine) direct connection
The critical invariant: order, customer, and product sync never transits the Worker. It flows on the bottom arrow, directly between your ERPClaw and Shopify. What the Worker does handle is the one-time token handoff, the status counts, and Shopify’s compliance requests (covered below).
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, issues a signed, timestamped state value (its nonce kept in KV for five minutes, single use), 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 Shopify’s HMAC and the state, 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, info="status-push:<shop>", L=32). (When the app loads embedded in Shopify Admin without this redirect, the admin UI gets the same kind of pairing code fromPOST /pair/init, which uses Shopify’s token exchange instead of the code grant.) - 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 overwrites the KV entry with a short-lived “consumed” marker. The code is single-use: a second read gets an error, not the token. - 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: the Worker keeps no customer records of its own. It queues the request, with Shopify’s payload (the customer’s identifiers and any affected order IDs), as agdpr-dispatchcommand, where it waits until your ERPClaw collects and acknowledges it.customers/redact: same path; your ERPClaw records the request in its audit log, and the redaction itself is a step you run.shop/redact: fired 48 hours after uninstall. The Worker queues it for your ERPClaw and deletes the shop’s status blob, HMAC secret, and install state from KV. ERPClaw preserves GL entries (immutable; covered by GDPR Article 17(3)(b) exception for tax and accounting).app/uninstalled: the Worker queues it for your ERPClaw; the shop’s KV state is cleared whenshop/redactarrives.
Data location summary
| Data | Where it lives | Retention |
|---|---|---|
| Shop domain | Cloudflare KV key names (status:, shop:, commands:) |
Until shop/redact |
| OAuth access token | Cloudflare KV (pair:{code}) during handoff only |
10 min max, removed on redemption |
| Per-shop HMAC secret | Cloudflare KV (shop:{shop}:hmac), plus a copy held by your ERPClaw |
On the Worker until shop/redact (it verifies your status pushes); indefinite on your ERPClaw |
| Status blob | Cloudflare KV (status:{shop}) |
One hour, refreshed on each push |
| Queued commands, including compliance request payloads | Cloudflare KV (commands:{shop}) |
Until your ERPClaw acknowledges them, 28 days at most |
| Orders, customers, products | Your ERPClaw database (SQLite default or PostgreSQL) | Indefinite; you control it |
| GL entries | Your ERPClaw database (SQLite default or PostgreSQL) | 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