More Shopify documentation
Shopify GDPR Webhooks: Data Requests and Redaction
How the ERPClaw Shopify integration handles the four mandatory GDPR webhooks: data request, customer redact, shop redact, and app uninstalled.
Shopify mandates four compliance webhooks on every published app. This page documents how ERPClaw handles each one, what data we hold where, and what your obligations are as the data controller.
The four webhooks
| Topic | Fired when | Worker behavior | ERPClaw behavior |
|---|---|---|---|
customers/data_request |
Merchant requests data export for a customer | Verifies HMAC, queues gdpr-dispatch for your ERPClaw, returns 200 |
Records the request and writes a receipt file (shop, Shopify customer ID, timestamp) for you to act on; assembling the export is a step you run |
customers/redact |
10 days after merchant-requested customer deletion | Verifies HMAC, queues gdpr-dispatch, returns 200 |
Records the request in the GDPR log for you to act on; redacting the customer’s details is a step you run |
shop/redact |
48 hours after shop uninstall | Verifies HMAC, deletes the shop’s status blob, HMAC secret, and install state, queues gdpr-dispatch for your ERPClaw, returns 200 |
Deletes the Shopify connector rows for that shop (synced orders, refunds, payouts, disputes, products, customers, sync jobs); GL entries are preserved |
app/uninstalled |
Immediately on app uninstall | Verifies HMAC, queues gdpr-dispatch, returns 200 |
Flags the connection so status pushes stop; local data stays until shop/redact |
Verification is constant-time HMAC-SHA256 against the
SHOPIFY_CLIENT_SECRET environment variable, per Shopify’s
webhook signature spec.
Why the Worker forwards instead of acting
The Worker holds no merchant business records: no order amounts, no financial totals, no customer list. So when Shopify asks “give me everything you have about customer X”, the Worker has nothing of its own to give.
Your ERPClaw holds the records. So the Worker queues a gdpr-dispatch
command in Cloudflare KV with the shop, the topic, and the inbound
payload (for customer requests, Shopify’s payload carries the
customer’s identifiers and the affected order IDs). The command waits
there until your ERPClaw picks it up on the next status check-in (or
via SSE if active) and acknowledges it, 28 days at most.
This means:
- The only customer details that touch our infrastructure are the ones inside Shopify’s compliance requests, held in the queue until your ERPClaw collects them.
- Your ERPClaw is the data controller, and you handle the GDPR obligations for the data you hold.
- The Worker is only a relay; we hold data minimization to the furthest extent possible.
What ERPClaw does on customers/redact
When the customers/redact command reaches your ERPClaw, it records
the request (shop, connector account, Shopify customer ID, timestamp)
in the local GDPR log at ~/.openclaw/erpclaw/logs/shopify_gdpr.log.
Automated per-customer redaction is not built yet, so updating the
customer’s name, email, phone, and addresses in your ERPClaw is a step
you run, and the log entry is your record that the request arrived.
Whatever you redact:
- GL entries are preserved. ERPClaw’s general ledger is immutable by design; redacting GL entries would break the chain of custody and violate accounting record-keeping requirements (US GAAP, IRS Pub 583, GDPR Article 17(3)(b) exception for legal obligations).
- Stock ledger entries (SLE) are preserved for the same reason.
What shop/redact actually deletes
When shop/redact fires (48 hours after uninstall), the Worker
deletes:
status:{shop}(status blob with sync counters)shop:{shop}:hmac(the per-shop HMAC secret)install:{shop}:state(any leftover install state)
Pairing codes have already expired by then (ten-minute lifetime). Queued commands expire on their own within 28 days, and webhook deduplication markers within 7 days.
ERPClaw receives a gdpr-dispatch command with topic shop/redact
and deletes the Shopify connector rows for that shop: synced orders
and their lines, refunds, payouts and payout transactions, disputes,
products and variants, Shopify customer records, sync jobs, and the
connection itself. GL entries are preserved, and so are your core
ERPClaw customer and item records. You can delete the local DB
manually if you want a clean wipe.
Data we never hold (GDPR negative-confirmation)
For audit purposes, here is what our Worker does not store as records (the one exception is the customer identifiers inside a Shopify compliance request, held in the command queue until your ERPClaw collects it):
- Customer names, emails, phone numbers, addresses
- Order line items, amounts, products
- Product details, SKUs, prices
- Inventory levels, warehouses
- Financial entries (invoices, payments, GL entries)
- Payout amounts (we hold counters, not amounts)
- Tax IDs, tax registration numbers
You can verify this by reading the Worker source at github.com/avansaber/erpclaw-addons and grepping for any of the above field names. They do not appear.
Audit trail
If you need a GDPR Article 30 records-of-processing trail for an audit, the following are available:
- Worker access logs: Cloudflare Logpush to R2, 90-day retention.
- GDPR webhook receipt log: the Worker writes a log line for every received compliance webhook with topic, shop, and event ID (it is part of the Worker request logs above).
- ERPClaw GDPR log: every compliance request your ERPClaw processes is appended to
~/.openclaw/erpclaw/logs/shopify_gdpr.logwith timestamp, topic, shop, and detail (Shopify customer ID for customer requests, rows deleted forshop/redact).
Where to test the flow
The shopify shopify-handle-gdpr action accepts a --topic and
--payload for offline testing. See the action documentation in the
SKILL.md source.
Privacy policy
Our public privacy policy for the Shopify integration is at avansaber.com/privacy-shopify.
For questions about the GDPR webhook flow, email
[email protected].