Webhooks
There is a built method to listen for webhooks sent by Shopify back to your application. These are validated based on a secret you received when setting them up.
Registering Webhooks
Via the Command Line (recommended)
The easiest way to register all webhooks is to run the built-in Artisan command. It will query your Shopify store, skip any that are already registered, and create any that are missing.
php artisan shopify:webhooks:register
In multi-store mode you can target a specific store:
php artisan shopify:webhooks:register --store=uk
If --store is omitted in multi-store mode, the command iterates all configured stores.
The command outputs a table showing the topic, callback URL, and whether each webhook was already registered, newly registered, or failed.
The command requires your Shopify credentials to be configured and your application's APP_URL to be set correctly, so that the callback URLs it generates are publicly accessible.
Via the Shopify Admin
You can also register webhooks manually:
- Head to your Shopify admin
- Click Settings > Notifications
- Scroll down to Webhooks and click Create Webhook
- Enter the URL as shown in the sections below.
- Leave the type as
JSONand on the latest API. - If this is your first webhook, you will be provided a secret which you should add to your .env as
SHOPIFY_WEBHOOK_SECRET
If you are trying to test any webhooks locally you'll need to use a service like Ngrok to forward your localhost to a secure endpoint.
Webhook Status
The Shopify Control Panel dashboard includes a Webhook Status card that queries your Shopify store and shows which webhooks are registered, whether their callback URLs match what the addon expects, and which topics are missing.
For any missing topics, run php artisan shopify:webhooks:register to create them automatically.
Webhook Endpoints
The following endpoints are registered by the addon. All webhook URLs follow the pattern:
https://YOURSITE/!/shopify/webhook/{resource}/{action}
| Topic | URL |
|---|---|
| Collection Create | /!/shopify/webhook/collection/create |
| Collection Update | /!/shopify/webhook/collection/update |
| Collection Delete | /!/shopify/webhook/collection/delete |
| Product Create | /!/shopify/webhook/product/create |
| Product Update | /!/shopify/webhook/product/update |
| Product Delete | /!/shopify/webhook/product/delete |
| Customer Create | /!/shopify/webhook/customer/create |
| Customer Update | /!/shopify/webhook/customer/update |
| Customer Delete | /!/shopify/webhook/customer/delete |
| Order Created | /!/shopify/webhook/order |
Shopify will send the product update webhook on creation too, so a separate product/create webhook is optional for most setups.
The Order Created webhook scans all line_items and re-fetches the product data for each.
Multi-Store
In multi-store mode, the same webhook URLs are used for all stores. Configure a separate set of webhooks in each Shopify admin pointing to the same Statamic endpoints.
Shopify always sends an X-Shopify-Shop-Domain header with every webhook request. The addon uses this header to:
- Identify which store the webhook came from (matched against each store's
urlin config). - Verify the HMAC signature using that store's
webhook_secret. - Pass the resolved store handle to any import jobs dispatched.
Each store's webhook secret must be set individually. See Env Values for the per-store env var pattern (SHOPIFY_STORE_{HANDLE}_WEBHOOK_SECRET).
Events
Each webhook listener also fires an event you can use to hook into with your own logic based on the payload received.
The available events are:
StatamicRadPack\Shopify\Events\CollectionCreate
StatamicRadPack\Shopify\Events\CollectionDelete
StatamicRadPack\Shopify\Events\CollectionUpdate
StatamicRadPack\Shopify\Events\CustomerCreate
StatamicRadPack\Shopify\Events\CustomerDelete
StatamicRadPack\Shopify\Events\CustomerUpdate
StatamicRadPack\Shopify\Events\ProductCreate
StatamicRadPack\Shopify\Events\ProductDelete
StatamicRadPack\Shopify\Events\ProductUpdate
StatamicRadPack\Shopify\Events\OrderCreate
Each event has one property $data with the payload data decoded to a stdClass.
For import job failures, see ProductImportFailed documented in Importing Data.