WooCommerce webhook not firing?

An order comes in, and the webhook you configured never reaches your app. No error on the store, no error in your logs — WooCommerce webhooks fail quietly, in three specific ways: delivery is deferred to a cron queue that may not be running, the webhook gets silently disabled after 5 consecutive failures, and the activation ping demands a literal HTTP 200. Here's how to diagnose each one, fastest check first.

1. First, separate "not sending" from "not receiving"

Point the webhook at a neutral capture URL so your own endpoint is out of the loop. Create a bin (button below, or curl https://hookden.pages.dev/new), then in WooCommerce → Settings → Advanced → Webhooks set it as the Delivery URL and place a test order.

Bins respond 200 by default, so the activation ping (step 5) passes and you'll see every delivery with full headers — X-WC-Webhook-Topic, X-WC-Webhook-Resource, X-WC-Webhook-Event, X-WC-Webhook-Signature, X-WC-Webhook-Delivery-ID — plus the exact JSON body your handler must parse.

2. Deliveries are late or bursty: it's WP-Cron

Since WooCommerce 3.5.0, webhooks are delivered asynchronously through Action Scheduler, which runs on WP-Cron — and WP-Cron only runs when someone visits the site. On a quiet staging store, a webhook can sit queued for minutes (or until the next visit) after the order that triggered it.

3. Deliveries stopped entirely: the silent 5-failure disable

WooCommerce counts any response that isn't a 2xx, 301, or 302 as a failed delivery — a 404, a 500, a timeout, all count. After 5 consecutive failures it sets the webhook's status to disabled and stops trying. There is no email, no admin notice, and core WooCommerce does not retry a failed delivery — each failure is simply counted.

4. Verify X-WC-Webhook-Signature correctly

WooCommerce signs the payload with HMAC-SHA256(secret, raw body), base64-encoded, in X-WC-Webhook-Signature. Two classic mistakes:

To check your math against reality: open a captured delivery in the bin, paste your secret, and the signature badge shows ✓/✗ against the raw bytes WooCommerce actually sent — before you touch your own code. Verifying against re-serialized JSON instead of the raw request body is the same bug that bites Stripe and Shopify integrations.

5. "Delivery URL cannot be reached" when activating

When you activate a webhook, WooCommerce sends a ping (body webhook_id=…) to the Delivery URL and requires the response code to be exactly 200 — a 204, a redirect, or an endpoint that validates the body and returns 4xx will block activation with "Error: Delivery URL cannot be reached". Make sure your endpoint returns a plain 200 for the ping (or activate against a bin first to confirm the store side works, then switch the URL).

6. Developing locally? Your store can't reach localhost

A live store can't deliver to http://localhost:3000, and the activation ping will fail before you even get that far. Instead of a tunnel, give WooCommerce a stable capture URL and relay deliveries down to your machine:

$ curl -s https://hookden.pages.dev/cli -o hookden && chmod +x hookden
$ curl https://hookden.pages.dev/new
$ ./hookden relay YOUR_BIN http://localhost:3000

Bodies are re-delivered byte-identical, so X-WC-Webhook-Signature still verifies in your real handler. Details: webhooks to localhost without a tunnel.

No signup needed. Or from your terminal: curl https://hookden.pages.dev/new

← All guides · Docs · Hookden vs webhook.site