Skip to main content

Shopify webhooks

What Sumeru subscribes to

Sumeru subscribes to ~25 Shopify webhook topics. The list is declared in app installation; merchants approve at OAuth.

Topic catalog

Customer events

TopicUse
customers/createNew customer → create Customer 360 row
customers/updateUpdate Customer 360
customers/delete(Pre-redact lifecycle)

Order events

TopicUse
orders/createNew order → attribution + journey enrollment
orders/updatedStatus changes
orders/cancelledReverse fulfillment journeys
orders/fulfilledTrigger review-request journey
orders/paidTrigger post-purchase upsell

Product / inventory

TopicUse
products/createSync to multichannel feeds
products/updateSync changes
products/deleteRemove from feeds
inventory_levels/updateReal-time stock sync to marketplaces

Cart events

TopicUse
carts/createTrack for cart-recovery
carts/updateUpdate tracking
checkouts/createPre-purchase attribution touchpoint
checkouts/updateCart-abandonment trigger

App lifecycle

TopicUse
app/uninstalledTrigger 30-day data retention countdown
app_subscriptions/updatePlan-tier change

GDPR (mandatory)

TopicUse
customers/data_requestExport customer data
customers/redactErase customer data
shop/redactErase entire shop's data (after uninstall + 30d)

HMAC verification

Shopify signs every webhook with HMAC-SHA256:

Header: X-Shopify-Hmac-Sha256: <base64>
Body: raw JSON

Verification:

import crypto from 'node:crypto';

function verifyShopifyWebhook(rawBody, hmacHeader, sharedSecret) {
const computed = crypto
.createHmac('sha256', sharedSecret)
.update(rawBody)
.digest('base64');
try {
return crypto.timingSafeEqual(
Buffer.from(hmacHeader),
Buffer.from(computed)
);
} catch {
return false;
}
}

Fail = 401, no processing.

Payload examples

orders/create (excerpt)

{
"id": 5234567890,
"email": "jane@example.com",
"created_at": "2026-05-10T14:23:00Z",
"total_price": "67.50",
"currency": "USD",
"customer": {
"id": 9876543210,
"email": "jane@example.com"
},
"line_items": [ ... ]
}

Full Shopify payload schemas: Shopify Webhook Reference.

GDPR webhook contract

Shopify mandates 3 GDPR webhooks for every app:

customers/data_request — export

When fired:

  1. Sumeru collects all customer data (Customer 360, events, messages, attributions, opt-ins)
  2. Generates JSON export
  3. Posts back to merchant's contact email or data_request_url per Shopify's contract
  4. Logs to GdprRequest with status=completed

SLA per Shopify: 30 days. Sumeru typically delivers within 1 hour.

customers/redact — erase

When fired:

  1. Run erase pipeline
  2. PII nulled in Customer 360
  3. Identity links deleted
  4. Active journeys exited
  5. Audit log written

SLA per Shopify: 30 days. Sumeru typically processes immediately.

shop/redact — full data erase

Fired 30 days after app uninstall. Removes all shop data permanently.

Idempotency

Each Shopify webhook has unique X-Shopify-Webhook-Id header. Sumeru uses this for dedup.

Retry behavior

Shopify retries failed webhooks up to 48 hours with exponential backoff. Sumeru acks within 2 sec to avoid unnecessary retries.

Common gotchas

"Not receiving customers/redact webhooks." Verify Sumeru is registered in your Shopify GDPR webhook section. Re-install if missing.

"Order webhook arrived after Sumeru was already in maintenance." Shopify will retry; on next online cycle, queue drains.

See also