← Back to Blog
Guide shopify webhooks ecommerce setup hmac

How to Set Up Shopify Webhooks: A Complete Developer Guide

Shopify's webhook system is powerful but has some quirks worth knowing about — HMAC verification, topic-based subscriptions, delivery guarantees, and handling the 5-second timeout. Here's the full setup guide.

JW

Jason Warner

March 21, 2026

How to Set Up Shopify Webhooks: A Complete Developer Guide

Shopify webhooks let your application react to store events in near real-time: orders created, customers updated, products changed, payments processed. Setting them up is straightforward, but there are a few important details — particularly around signature verification and the response timeout — that you need to get right.

Common Shopify Webhook Topics

  • orders/create, orders/updated, orders/paid, orders/cancelled, orders/fulfilled
  • customers/create, customers/update, customers/delete
  • products/create, products/update, products/delete
  • checkouts/create, checkouts/update
  • inventory_levels/update
  • app/uninstalled

Creating a Webhook Subscription

Via the Admin UI

Settings → Notifications → Webhooks → Create webhook → select topic and enter your endpoint URL.

Via the REST API

POST /admin/api/2024-01/webhooks.json
{
  "webhook": {
    "topic": "orders/create",
    "address": "https://your-app.com/webhooks/shopify/orders",
    "format": "json"
  }
}

Via GraphQL

mutation {
  webhookSubscriptionCreate(
    topic: ORDERS_CREATE
    webhookSubscription: {
      callbackUrl: "https://your-app.com/webhooks/shopify/orders"
      format: JSON
    }
  ) {
    webhookSubscription { id }
    userErrors { field message }
  }
}

The 5-Second Rule

Shopify requires your endpoint to respond within 5 seconds. If it takes longer, Shopify marks it as failed and retries.

Respond immediately, process asynchronously:

app.post('/webhooks/shopify/orders', (req, res) => {
  res.sendStatus(200); // respond immediately
  processOrderAsync(req.body).catch(err => console.error(err));
});

HMAC Signature Verification

Every Shopify webhook includes X-Shopify-Hmac-Sha256 — a Base64-encoded HMAC-SHA256 of the request body, signed with your app's client secret. Always verify this.

const crypto = require('crypto');

function verifyShopifyWebhook(req, secret) {
  const hmac = req.headers['x-shopify-hmac-sha256'];
  const hash = crypto
    .createHmac('sha256', secret)
    .update(req.body) // MUST be raw buffer, not parsed JSON
    .digest('base64');
  return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(hash));
}

app.post('/webhooks/shopify/orders',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    if (!verifyShopifyWebhook(req, process.env.SHOPIFY_SECRET)) {
      return res.sendStatus(401);
    }
    res.sendStatus(200);
    processOrderAsync(JSON.parse(req.body)).catch(console.error);
  }
);

Critical: You must use the raw request body for HMAC. Use express.raw() or equivalent — not express.json().

Handling Retries and Idempotency

Shopify retries failed deliveries up to 19 times over 48 hours. Your handler must be idempotent. Use X-Shopify-Webhook-Id as your idempotency key:

const webhookId = req.headers['x-shopify-webhook-id'];
const alreadyProcessed = await db.processedWebhooks.findOne({ id: webhookId });
if (alreadyProcessed) return res.sendStatus(200);

await db.processedWebhooks.create({ id: webhookId });
// process...

Using Bluejay Relay for Shopify Webhooks

Point all your Shopify webhook topics at a single Bluejay Relay integration URL. Bluejay Relay handles:

  • Signature verification: Built-in Shopify HMAC verification
  • Fan-out: Deliver orders/create to your order service, analytics, and fulfillment provider simultaneously
  • Retry: Configurable backoff if your downstream service is down
  • Replay: Re-send historical orders without triggering new Shopify events

Set up Shopify webhook routing free on Bluejay Relay — handles verification, delivery logging, retry, and fan-out out of the box.

#shopify #webhooks #ecommerce #setup #hmac

Build more reliable webhook workflows.

Capture, transform, and retry webhooks with full observability. Free to start, no credit card.