Skip to main content

Shopify GDPR Webhooks - How ERPClaw Handles Data Requests + Redaction

How the ERPClaw Shopify integration handles the four mandatory GDPR webhooks: customers/data_request, customers/redact, shop/redact, app/uninstalled. Source-verifiable + audit-ready.

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

TopicFired whenWorker behaviorERPClaw behavior
customers/data_requestMerchant requests data export for a customerVerifies HMAC, queues gdpr-dispatch for your ERPClaw, returns 200Generates JSON export of all customer-related rows, mails to merchant
customers/redact10 days after merchant-requested customer deletionVerifies HMAC, queues gdpr-dispatch, returns 200Redacts customer PII from local DB; preserves anonymized order/financial records
shop/redact48 hours after shop uninstallVerifies HMAC, deletes all *:{shop} KV keys, queues final gdpr-dispatch for your ERPClaw, returns 200Receives final cleanup signal; merchant decides what to redact locally
app/uninstalledImmediately on app uninstallVerifies HMAC, drops KV state for the shop, returns 200Local ERPClaw data preserved; merchant retains control

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 data: no customer names, no order amounts, no financial totals. So when Shopify asks “give me everything you have about customer X”, the Worker has nothing to give.

But your ERPClaw does. So the Worker queues a gdpr-dispatch command in Cloudflare KV with the shop, the topic, and the inbound payload. Your ERPClaw picks it up on the next status check-in (or via SSE if active), runs the actual data request or redaction against its local SQLite database, and emails the result to the merchant.

This means:

  • No customer data lives on our infrastructure, so we have no GDPR Article 30 record-of-processing obligation for the bulk of the data.
  • 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 redacts on customers/redact

When the customers/redact command reaches your ERPClaw, the following happens locally:

  1. The customer’s customer.name, customer.email, customer.phone, customer.billing_address, customer.shipping_address columns are set to anonymized placeholders (e.g., name = 'REDACTED-{customer_id}').
  2. Linked rows that contain customer PII (sales invoices, sales orders, delivery notes) have their customer_name field anonymized too.
  3. 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).
  4. Stock ledger entries (SLE) are preserved for the same reason.
  5. The redaction event is logged in data_audit_log so you can prove the request was honored.

What shop/redact actually deletes

When shop/redact fires (48 hours after uninstall), the Worker deletes:

  • meta:{shop} (shop domain, owner email)
  • status:{shop} (status blob with sync counters)
  • pair:* keys still associated with the shop (should be empty by then)
  • Any pending cmd:*:{shop} command queues
  • Any pending dedup:*:{shop} deduplication state

ERPClaw receives a gdpr-dispatch command with topic shop/redact. By design, ERPClaw does not delete your local SQLite data on this signal. The merchant’s local install is theirs to control. 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 does not exist anywhere on our Worker, never has, and never will:

  • 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: every received webhook is logged with topic, shop, timestamp, and HMAC verification result. Available in gdpr_webhook_log Cloudflare KV index.
  • ERPClaw data_audit_log: every redaction or data request your ERPClaw processes is logged locally with timestamp, customer_id, requestor email, and outcome.

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].