Skip to main content
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:

  1. 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).
  2. 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.log with timestamp, topic, shop, and detail (Shopify customer ID for customer requests, rows deleted for shop/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].