Webhooks
The Nuxt Shopify module provides functionality for managing webhook subscriptions and runtime request HMAC validation.
Configuration
To get started, you need to configure your webhooks in the nuxt.config.ts file.
You need to provide your Shopify App Client Secret and a list of hooks you want to subscribe to.
export default defineNuxtConfig({
modules: ['@nuxtjs/shopify'],
shopify: {
webhooks: {
secret: process.env.SHOPIFY_CLIENT_SECRET,
hooks: [
{
topic: 'ORDERS_CREATE',
uri: 'https://your-app.com/api/webhooks/orders-create',
},
{
topic: 'PRODUCTS_UPDATE',
uri: 'https://your-app.com/api/webhooks/products-update',
}
],
},
},
})
Options
| Option | Type | Description |
|---|---|---|
secret | string | Your Shopify App Client Secret. Used for HMAC validation. |
hooks | Webhook[] | An array of webhooks to subscribe to. |
Each webhook in the hooks array can have the following properties:
topic(required): The topic of the webhook (e.g.ORDERS_CREATE).uri(required): The URI where the webhook should be sent.format(optional): The format of the webhook payload (JSONorXML). Defaults toJSON.filter(optional): A filter for the webhook.includeFields(optional): A list of fields to include in the webhook payload.metafieldNamespaces(optional): A list of metafield namespaces to include.metafields(optional): A list of metafields to include.
Managing Webhooks
The module provides a CLI command to easily manage your webhook subscriptions from your local development environment.
List Subscribed Webhooks
To list all currently subscribed webhooks for your shop:
npx @nuxtjs/shopify@latest webhooks list
Subscribe to Webhooks
To subscribe to the webhooks configured in your nuxt.config.ts:
npx @nuxtjs/shopify@latest webhooks subscribe
This command will read your configuration and create subscriptions for any webhooks that are not already subscribed.
Unsubscribe from Webhooks
To unsubscribe from all webhooks configured in your nuxt.config.ts:
npx @nuxtjs/shopify@latest webhooks unsubscribe
Handling Webhooks
To securely handle incoming webhooks, the module provides the defineWebhookEventHandler utility.
This handler automatically validates the incoming request against your Shopify App Client Secret using HMAC validation.
Create a new server route (e.g. server/api/webhooks/orders-create.ts) and use defineWebhookEventHandler:
// server/api/webhooks/orders-create.ts
export default defineWebhookEventHandler(async (event) => {
const body = await readBody(event)
const topic = getWebhookTopic(event)
const shop = getWebhookShopDomain(event)
console.log(`Received ${topic} webhook from ${shop}`)
console.log('Payload:', body)
// Handle the webhook payload
})
If the validation fails, the handler will automatically return a 401 Unauthorized response.
webhooks.secret is set, in development as well as in production.
Only the case of a missing secret differs: nuxt dev accepts the request with a warning so local
testing is possible, while a production build rejects it with a 401.Helper Functions
The module provides several helper functions to extract information from the webhook request. These are available in your server routes:
getWebhookTopic(event): Returns the webhook topic.getWebhookShopDomain(event): Returns the shop domain.getWebhookHmac(event): Returns the HMAC signature.getWebhookApiVersion(event): Returns the API version.getWebhookId(event): Returns the webhook ID.getWebhookTriggeredAt(event): Returns the timestamp when the webhook was triggered.getWebhookEventId(event): Returns the event ID.
Validating Manually
If you cannot wrap your route in defineWebhookEventHandler - for example when the same route serves other traffic,
or when you need to run logic before validation - call the auto-imported validateWebhook helper yourself.
It performs the same HMAC check and throws a 401 Unauthorized error when the signature does not match:
export default defineEventHandler(async (event) => {
await validateWebhook(event)
const body = await readBody(event)
// Handle the webhook payload
})
validateWebhook reads the raw request body to compute the signature. Read the body afterwards, as shown above.