
Shopify fires webhooks for orders, products, customers, fulfillments, refunds, app lifecycle, and dozens of other store events. They're how integrations stay in sync with what's happening in a Shopify store without polling the API.
This guide covers what Shopify sends, how to verify it, and what production reliability requires beyond a basic handler — including the failure mode that silently kills your integration.
What Shopify sends
Shopify webhooks are JSON POSTs. An orders/paid event:
{
"id": 820982911946154508,
"email": "customer@example.com",
"created_at": "2026-04-24T14:30:00Z",
"currency": "USD",
"current_total_price": "29.99",
"financial_status": "paid",
"fulfillment_status": null,
"line_items": [
{
"id": 866550311766439020,
"title": "T-Shirt",
"quantity": 1,
"price": "29.99"
}
],
"customer": { "id": 115310627314723954, "email": "customer@example.com" }
}
The metadata is in headers, not the body:
X-Shopify-Topic: orders/paid
X-Shopify-Hmac-SHA256: <base64 signature>
X-Shopify-Shop-Domain: yourshop.myshopify.com
X-Shopify-API-Version: 2025-01
X-Shopify-Webhook-Id: 12345678-abcd-1234-abcd-1234567890ab
Shopify has 100+ webhook topics. Subscribe only to the ones your integration needs — fewer events means simpler handling.
Shopify's signature scheme
The signature is HMAC-SHA256 of the raw body using the webhook secret, base64-encoded:
X-Shopify-Hmac-SHA256: 5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd=
Verification:
- Read the raw body before any JSON parsing
- Compute
base64(HMAC-SHA256(secret, raw_body)) - Compare constant-time with the header value
There's no timestamp in the signature, so replay protection is your job — use the X-Shopify-Webhook-Id UUID for idempotency.
Shopify's retry policy (and the silent-removal trap)
Shopify retries failed webhook calls up to eight times over roughly four hours. This is useful, but it still has a hard cutoff.
The trap: if Shopify's retries fail too many times in a row to the same endpoint, Shopify will automatically remove the webhook subscription. Silent failure cascades into silent loss of integration. You have to monitor for it; Shopify won't tell you.
This means:
- Acknowledge fast. 5-second budget; do real work async.
- Be idempotent on
X-Shopify-Webhook-Id— duplicates will arrive during retries. - Monitor delivery success. If too many fail in a row, your subscription disappears without warning.
- Have a recovery story for events that exhaust Shopify's retry window.
DIY: minimal Shopify webhook handler in Node
import { createHmac, timingSafeEqual } from 'crypto'
const secret = process.env.SHOPIFY_WEBHOOK_SECRET!
export async function POST(req: Request) {
const sig = req.headers.get('x-shopify-hmac-sha256')!
const topic = req.headers.get('x-shopify-topic')!
const webhookId = req.headers.get('x-shopify-webhook-id')!
const body = await req.text()
const expected = createHmac('sha256', secret).update(body).digest('base64')
if (!timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return new Response('Bad signature', { status: 401 })
}
// Idempotency on `webhookId`
// ...
const payload = JSON.parse(body)
queueWork(topic, payload)
return new Response('ok', { status: 200 })
}
Production needs more:
- A persistence layer for the
X-Shopify-Webhook-Ididempotency check - A queue for async work (5-second budget)
- A retry policy when
queueWorkfails - A replay path for events older than Shopify's retry window
- Monitoring that warns before Shopify silently unsubscribes you
- Filtering — large stores produce huge volumes of low-value events
- Multi-shop support — one signing secret per shop in a multi-tenant app
Hooksbase: receive Shopify webhooks without rebuilding the rest
Shopify isn't one of Hooksbase's five pre-verified provider packs (Stripe, GitHub, Clerk, Slack, Resend), and Hooksbase does not forward Shopify's original HMAC headers to your destination. If you need Shopify HMAC verification, verify it in a small pre-ingest forwarder, then post the verified raw body to Hooksbase with the bearer ingest secret.
Setup:
- Create a webhook in Hooksbase with your application URL as the destination
- Configure Shopify to send to your verification forwarder
- In the forwarder, verify
X-Shopify-Hmac-SHA256, then POST the same raw body to the Hooksbase ingest URL withAuthorization: Bearer <ingest secret>
You get:
- Idempotency for your destination — every dispatch includes a unique
webhook-idheader (Standard Webhooks-compatible) you can dedupe on across retries. If your handler needs Shopify's webhook ID, include it in the forwarded payload or verify/store it in the pre-ingest forwarder. - Retries with exponential backoff to your endpoint after Hooksbase accepts the event
- Acknowledge in milliseconds to Shopify regardless of how slow your downstream is — you don't lose the subscription to slow handlers
- Routing rules by
X-Shopify-Topicduring ingest — sendorders/paidto one destination,customers/createto another - Payload transforms — extract just the fields your downstream needs
- Deterministic replay — re-run a failed delivery with the same payload bytes while the payload is retained
- Delivery history and DLQ
- Failure-spike alerts (Pro+) — get warned when downstream delivery starts failing
Common Shopify webhook use cases for AI agents
- Order fulfillment agent —
orders/paidevents trigger an agent that decides fulfillment routing (warehouse, dropship, digital), updates the inventory system, and emails the customer - Refund triage agent —
refunds/createevents trigger an agent that classifies the refund reason and flags patterns for the merch team - Inventory alerting agent —
products/updateevents with low inventory trigger an agent that checks reorder rules and pings the buyer - Customer reactivation agent —
customers/createevents trigger an agent that enriches the profile and schedules a personalized welcome flow - App lifecycle agent —
app/uninstalledevents trigger an agent that runs your offboarding flow (data export, refund prorate, churn survey)
Where to go next
- How to receive Stripe webhooks reliably
- How to receive GitHub webhooks reliably
- Recover failed agent events for DLQ patterns
- How to build an AI agent
Start free at app.hooksbase.com.
Frequently asked questions
How do you verify a Shopify webhook signature?
Read the raw request body before any JSON parsing, compute HMAC-SHA256 of it with your webhook secret, base64-encode the result, and compare it constant-time against the X-Shopify-Hmac-SHA256 header. There is no timestamp in the signature, so use the X-Shopify-Webhook-Id UUID for idempotency and replay defence.
How long does Shopify retry a failed webhook?
Shopify retries a failed webhook call up to eight times over roughly four hours, then stops. Aim to acknowledge within a 5-second budget and do the real work asynchronously.
Why did Shopify delete my webhook subscription?
Shopify automatically removes a webhook subscription after too many consecutive delivery failures to the same endpoint. Nothing notifies you, so a period of downtime can turn into a permanently missing integration that looks like Shopify simply stopped sending events. Monitor your subscriptions rather than waiting to notice the silence.
What is Hooksbase?
Hooksbase is event infrastructure for AI agents. It ingests events over four channels — HTTP, email, HTML form, and scheduled cron — verifies them, routes them by rule, runs versioned Automations in the event path, and delivers them to HTTP and cloud destinations (AWS SQS, AWS EventBridge, GCP Pub/Sub, and S3-compatible storage) with retries, strict ordering, Standard Webhooks-compatible signing, deterministic replay, and a dead-letter path. It is a hosted service, runs on Cloudflare Workers, is operated at hooksbase.com, and is not affiliated with — and shares no code or ownership with — other similarly named webhook, hook, or tunnelling tools.