Webhook Guide
Shopify Webhook Testing
Store event webhooks for orders, customers, products
Quick path: CLI helper commands
Use these first to avoid setup mistakes, then follow the full provider steps below.
instatunnel webhook init --provider shopify --port 3000 --path /webhooks/shopify
instatunnel webhook verify --provider shopify --secret-env SHOPIFY_WEBHOOK_SECRET
instatunnel webhook test --provider shopify
If you run into provider-specific issues, use the full checklist sections below.
1. Local app setup
Create a local webhook endpoint at: /webhooks/shopify
import express from 'express'
import crypto from 'crypto'
const app = express()
app.post('/webhooks/shopify', express.raw({ type: 'application/json' }), (req, res) => {
const hmac = req.header('x-shopify-hmac-sha256') || ''
const rawBody = req.body as Buffer
const digest = crypto
.createHmac('sha256', process.env.SHOPIFY_WEBHOOK_SECRET!)
.update(rawBody)
.digest('base64')
const hmacBuf = Buffer.from(hmac)
const digestBuf = Buffer.from(digest)
const valid = hmacBuf.length === digestBuf.length && crypto.timingSafeEqual(hmacBuf, digestBuf)
if (!valid) {
return res.status(401).send('invalid hmac')
}
console.log('shopify topic:', req.header('x-shopify-topic'))
res.status(200).send('ok')
})
app.listen(3000, () => console.log('listening on :3000'))2. Run InstaTunnel command
instatunnel 3000 --subdomain shopify-dev
Keep a fixed subdomain so your provider dashboard URL does not keep changing.
3. Provider config fields to paste
| Field | Value | Where/notes |
|---|---|---|
| Delivery URL | {{WEBHOOK_URL}} | Shopify Admin > Settings > Notifications > Webhooks |
| Format | JSON | Use JSON payloads |
| Event/topic | orders/create (example) | Select only required topics |
| Webhook API version | Latest stable | Keep app and webhook version aligned |
Use the helper below to generate exact values with your chosen subdomain and path.
One-Click Webhook Setup Helper
Generate copy-ready tunnel command, webhook URL, and provider config values.
Run InstaTunnel
instatunnel 3000 --subdomain shopify-devWebhook URL
https://shopify-dev.instatunnel.my/webhooks/shopify| Provider field | Value to paste | Notes |
|---|---|---|
| Delivery URL | https://shopify-dev.instatunnel.my/webhooks/shopify | Shopify Admin > Settings > Notifications > Webhooks |
| Format | JSON | Use JSON payloads |
| Event/topic | orders/create (example) | Select only required topics |
| Webhook API version | Latest stable | Keep app and webhook version aligned |
Tip: keep one stable subdomain per provider to avoid reconfiguring dashboards.
4. Send test event
- In Shopify Admin webhook settings, click "Send test notification".
- For app webhooks, use Shopify CLI trigger commands in a dev store.
- Confirm your endpoint logs topic, shop domain, and a 2xx response.
# Shopify CLI example (event names vary by app setup) shopify app webhook trigger --topic orders/create
5. Verify signature
Verify this header on every request: x-shopify-hmac-sha256
const digest = crypto
.createHmac('sha256', process.env.SHOPIFY_WEBHOOK_SECRET!)
.update(rawPayloadBuffer)
.digest('base64')
const valid = Buffer.from(req.header('x-shopify-hmac-sha256') || '').length === Buffer.from(digest).length &&
crypto.timingSafeEqual(Buffer.from(req.header('x-shopify-hmac-sha256') || ''), Buffer.from(digest))
if (!valid) return res.status(401).send('invalid hmac')6. Retries and idempotency
- Use webhook ID + topic + timestamp as dedupe keys.
- Process asynchronously and return 200 quickly.
- Treat webhook deliveries as at-least-once and potentially out-of-order.
7. Common failures and quick fixes
401 invalid hmac
Verify webhook secret and ensure you hash exact payload body.
No webhook after install
Confirm webhook subscription exists for the correct store and topic.
Parsing failures
Force JSON body parsing and validate expected schema by topic.