Skip to main content

Overview

The webhooks API provides functions for managing shop-specific webhook subscriptions and validating webhook requests. For most apps, app-specific webhooks are recommended. Access the webhooks API through your configured Shopify instance:
const shopify = shopifyApi({ /* config */ });
const webhooks = shopify.webhooks;

validate()

Validates an incoming HTTP webhook request from Shopify. This is the primary function you’ll use for both app-specific and shop-specific webhooks.

Signature

type Validate = (params: WebhookValidateParams) => Promise<WebhookValidation>;

Parameters

rawBody
string
required
The raw request body as a string.
rawRequest
any
required
The raw HTTP request object from your framework.
rawResponse
any
required
The raw HTTP response object from your framework.

Returns

Returns a Promise<WebhookValidation> with the following possible structures:

Valid Webhook

valid
true
Indicates the webhook is valid.
domain
string
The shop domain.
topic
string
The webhook topic (e.g., PRODUCTS_CREATE).
hmac
string
The HMAC signature from the request.
apiVersion
string
The API version of the webhook.
webhookId
string
The webhook ID (for webhooks).
eventId
string
The event ID.
subTopic
string
The webhook sub-topic (if applicable).

Invalid Webhook

valid
false
Indicates the webhook is invalid.
reason
WebhookValidationErrorReasonType
The reason for validation failure:
  • missing_headers - Required headers are missing
  • invalid_hmac - HMAC validation failed
  • invalid_body - Body is invalid
missingHeaders
string[]
Array of missing header names (when reason is missing_headers).

Example

app.post('/webhooks/products/create', async (req, res) => {
  // Express with express.text() middleware
  const validation = await shopify.webhooks.validate({
    rawBody: req.body, // Already a string from express.text()
    rawRequest: req,
    rawResponse: res,
  });
  
  if (!validation.valid) {
    console.error('Webhook validation failed:', validation.reason);
    return res.status(401).send('Unauthorized');
  }
  
  // Process the webhook
  console.log('Received webhook:', validation.topic);
  console.log('From shop:', validation.domain);
  
  // Parse the body
  const webhookData = JSON.parse(req.body);
  console.log('Product created:', webhookData.id);
  
  res.status(200).send('OK');
});

addHandlers()

Adds shop-specific webhook handlers to the library registry. Only needed for shop-specific webhooks. Use app-specific webhooks instead in most cases.

Signature

type AddHandlers = (handlers: AddHandlersParams) => void;

Parameters

handlers
Record<string, WebhookHandler | WebhookHandler[]>
required
An object mapping webhook topics to their handlers.

Handler Types

HTTP Handler

interface HttpWebhookHandler {
  deliveryMethod: DeliveryMethod.Http;
  callbackUrl: string;
  callback?: WebhookHandlerFunction;
  includeFields?: string[];
  metafieldNamespaces?: string[];
  subTopic?: string;
}

EventBridge Handler

interface EventBridgeWebhookHandler {
  deliveryMethod: DeliveryMethod.EventBridge;
  arn: string;
  includeFields?: string[];
  metafieldNamespaces?: string[];
}

PubSub Handler

interface PubSubWebhookHandler {
  deliveryMethod: DeliveryMethod.PubSub;
  pubSubProject: string;
  pubSubTopic: string;
  includeFields?: string[];
  metafieldNamespaces?: string[];
}

Example

import { DeliveryMethod } from '@shopify/shopify-api';

shopify.webhooks.addHandlers({
  PRODUCTS_CREATE: {
    deliveryMethod: DeliveryMethod.Http,
    callbackUrl: '/webhooks/products/create',
    callback: async (topic, shop, body, webhookId) => {
      const data = JSON.parse(body);
      console.log(`Product created in ${shop}:`, data.id);
    },
  },
  ORDERS_PAID: [
    {
      deliveryMethod: DeliveryMethod.Http,
      callbackUrl: '/webhooks/orders/paid',
      callback: async (topic, shop, body) => {
        const order = JSON.parse(body);
        await fulfillOrder(order);
      },
    },
    {
      deliveryMethod: DeliveryMethod.EventBridge,
      arn: 'arn:aws:events:us-east-1:123456789012:event-bus/shopify-webhooks',
    },
  ],
});

register()

Registers shop-specific webhooks with Shopify. Only needed for shop-specific webhooks.

Signature

type Register = (params: RegisterParams) => Promise<RegisterReturn>;

Parameters

session
Session
required
The session for the shop to register webhooks.

Returns

Returns a Promise<RegisterReturn> - an object mapping topics to their registration results.
[topic]
RegisterResult[]
Array of registration results for each topic.

Example

// First add handlers
shopify.webhooks.addHandlers({
  PRODUCTS_CREATE: {
    deliveryMethod: DeliveryMethod.Http,
    callbackUrl: '/webhooks/products/create',
  },
});

// Then register them
const result = await shopify.webhooks.register({ session });

console.log('Registration results:', result);
// {
//   PRODUCTS_CREATE: [
//     {
//       success: true,
//       deliveryMethod: 'http',
//       result: { ... },
//       operation: 'create'
//     }
//   ]
// }

process()

Processes an incoming shop-specific webhook request and calls the registered callback. Only needed for shop-specific webhooks.

Signature

type Process = (params: WebhookProcessParams) => Promise<void>;

Parameters

rawBody
string
required
The raw request body.
rawRequest
any
required
The raw HTTP request.
rawResponse
any
required
The raw HTTP response.

Example

app.post('/webhooks/products/create', async (req, res) => {
  await shopify.webhooks.process({
    rawBody: req.body,
    rawRequest: req,
    rawResponse: res,
  });
  
  res.status(200).send('OK');
});

getTopicsAdded()

Returns all topics that have been added to the registry.

Signature

type GetTopicsAdded = () => string[];

Example

const topics = shopify.webhooks.getTopicsAdded();
console.log('Registered topics:', topics);
// ['PRODUCTS_CREATE', 'ORDERS_PAID']

getHandlers()

Returns the handlers for a specific topic.

Signature

type GetHandlers = (topic: string) => WebhookHandler[] | undefined;

Example

const handlers = shopify.webhooks.getHandlers('PRODUCTS_CREATE');
console.log('Handlers for PRODUCTS_CREATE:', handlers);

Types

DeliveryMethod

enum DeliveryMethod {
  Http = 'http',
  EventBridge = 'eventbridge',
  PubSub = 'pubsub',
}

WebhookOperation

enum WebhookOperation {
  Create = 'create',
  Update = 'update',
  Delete = 'delete',
}

WebhookHandlerFunction

type WebhookHandlerFunction = (
  topic: string,
  shop_domain: string,
  body: string,
  webhookId: string,
  apiVersion?: string,
  subTopic?: string,
  context?: any,
) => Promise<void>;

Common Webhook Topics

Some commonly used webhook topics:
  • PRODUCTS_CREATE - Product created
  • PRODUCTS_UPDATE - Product updated
  • PRODUCTS_DELETE - Product deleted
  • ORDERS_CREATE - Order created
  • ORDERS_UPDATED - Order updated
  • ORDERS_PAID - Order paid
  • ORDERS_FULFILLED - Order fulfilled
  • CUSTOMERS_CREATE - Customer created
  • CUSTOMERS_UPDATE - Customer updated
  • CUSTOMERS_DELETE - Customer deleted
  • CUSTOMERS_DATA_REQUEST - GDPR data request
  • CUSTOMERS_REDACT - GDPR redaction request
  • SHOP_REDACT - GDPR shop data deletion
See all available topics

Notes

Use app-specific webhooks for most use cases. They’re easier to set up and don’t require shop-specific registration.Learn about app-specific vs shop-specific webhooks
The validate() function works for both app-specific and shop-specific webhooks.
Always validate webhooks before processing them to ensure they came from Shopify.
You must use express.text() or equivalent middleware to get the raw body for webhook validation.

Build docs developers (and LLMs) love