WooCommerce webhooks connect store events to CRMs, fulfilment systems, accounting tools and custom applications. Creating one in the dashboard takes minutes. Making the complete delivery path secure, observable and safe to retry takes more planning.
A webhook should be treated as an integration contract, not as a fire-and-forget notification. This guide shows how to choose the right topic, verify the signature, return the right response, prevent duplicate side effects and diagnose failures without changing live orders blindly.
Define the event contract before creating the webhook
Start with the business event and the downstream action. “Send order data” is too vague. “When a paid order becomes processing, create or update one fulfilment job using the WooCommerce order ID” is testable.
| Decision | Example | Failure to prevent |
|---|---|---|
| Source event | Order updated | Wrong topic or premature fulfilment |
| Receiver | Dedicated HTTPS endpoint | Posting customer data to the wrong URL |
| Identity check | Verify the WooCommerce signature | Accepting forged requests |
| Deduplication key | Delivery ID plus business resource ID | Duplicate shipment or CRM record |
| Success response | Fast 2xx after durable acceptance |
Timeouts and unnecessary failures |
| Recovery owner | Named integration maintainer | Silent disabled webhook |
WooCommerce supports order, product, coupon and customer events, along with Action and custom topics. Choose the narrowest event that represents the real workflow. Do not use a high-frequency update topic when only one state transition matters, and document which payload fields the receiver actually depends on.
Create the webhook with deliberate settings
- Go to WooCommerce → Settings → Advanced → Webhooks.
- Use a name that states the destination, environment and purpose.
- Set the status to Active only when the receiver is ready.
- Select the agreed topic and enter the exact HTTPS delivery URL.
- Generate and store a strong secret in the receiving system's secret manager.
- Save the webhook and verify the initial ping at the receiver.
WooCommerce's webhook documentation notes that saving an active webhook sends a ping to the delivery URL. Treat that ping as a connectivity check, not proof that production event processing works. Run a controlled test event with a recognizable test order.
Keep staging and production destinations, credentials and data separate. A cloned production webhook can send staging events into a live fulfilment system. ICT's WooCommerce staging checklist covers isolation steps for payments and notifications.
Verify the signature against the raw request body
WooCommerce sends an X-WC-Webhook-Signature header containing a Base64-encoded HMAC-SHA256 hash of the payload. The receiver should calculate the HMAC with its stored webhook secret over the exact raw request body, Base64-encode the result and compare it with a timing-safe function.
expected = base64(
hmac_sha256(webhook_secret, raw_request_body)
)
if not timing_safe_equal(expected, received_signature):
return 401
This pseudocode is language-neutral. Do not reserialize parsed JSON and expect the same signature; whitespace or field ordering can change. Read the raw bytes first, verify them, and only then parse the payload. Keep the secret out of logs and error messages. When rotating it, coordinate both sides so the receiver does not reject every delivery.
Acknowledge quickly, process safely
The receiver should validate the request, record the event durably and return a success response quickly. Slow CRM calls, PDF generation or inventory synchronization should usually continue in a queue after acceptance. A long synchronous chain makes the sender depend on every downstream service at once.
Do not return 200 before the event is durably recorded, because a process crash could lose it. Do not wait for every business side effect either. A useful boundary is: authenticate, validate, store the event or queue job, then acknowledge.
Set request-size and processing limits. Reject malformed or oversized payloads predictably. Log a correlation value such as the webhook delivery ID, topic, order ID, response code and elapsed time, but never the secret or full customer payload.
Make every side effect idempotent
Networks retry, operators replay and receivers can time out after completing work. Processing the same event twice must not create two shipments, invoices or leads.
Use a database uniqueness rule around the event key or the business operation. A “check then insert” sequence without a unique constraint can race when two workers run together. Store the outcome of the winning operation and let subsequent deliveries return the already-established result.
- For creating an integration record, use a unique source-system and source-resource key.
- For state changes, compare the current state before applying the transition.
- For inventory changes, store the event identity and use a transaction.
- For email or fulfilment jobs, enqueue once using a durable unique job key.
Idempotency does not replace signature verification. It limits duplicate effects; it does not prove that a request came from your store.
Diagnose a missing or failed delivery in layers
Start with evidence, not by recreating the webhook or replaying real orders.
| Layer | Check | What it tells you |
|---|---|---|
| Trigger | Did the expected store event occur? | Separates topic selection from delivery failure |
| Webhook status | Active, Paused or Disabled? | Shows whether WooCommerce will attempt delivery |
| WooCommerce log | Request, response code and response body | Confirms an attempt and receiver outcome |
| Network edge | TLS, DNS, firewall and redirect behaviour | Shows whether the request reached the application |
| Receiver log | Correlation ID and validation result | Separates signature, parsing and business errors |
| Downstream job | Queue state and final side effect | Shows whether acknowledgement hid later failure |
WooCommerce stores webhook logs under WooCommerce → Status → Logs; the current merchant webhook guide recommends filtering for the webhooks-delivery source. Compare timestamps and delivery identifiers across both systems.
WooCommerce can automatically disable a webhook after repeated unsuccessful deliveries. Current documentation describes more than five consecutive failures as the default threshold; responses outside 2xx, 301 and 302 count as failures. A disabled status is a symptom. Fix the receiver or routing problem, run a controlled test, and only then reactivate it.
Check background delivery without conflating systems
WooCommerce queues webhook delivery work. If store events are created but delivery attempts do not appear, background processing may be relevant. Inspect the webhook status and logs first, then the scheduled-action queue for the corresponding delivery work.
A large scheduled-action backlog can delay many store tasks, not just webhooks. Follow ICT's Scheduled Actions recovery guide to diagnose the queue without bulk-deleting jobs. Do not mark actions complete merely to clear the screen; that can discard work without delivering it.
Run a webhook acceptance-test matrix
| Test | Expected result |
|---|---|
| Initial ping | Receiver is reachable; event processing is not triggered accidentally |
| Valid signed event | Accepted once and acknowledged within the agreed time |
| Invalid signature | Rejected without parsing or side effects |
| Duplicate delivery | Same business result; no duplicate side effect |
| Malformed payload | Predictable client error and privacy-safe log entry |
| Receiver outage | Visible failure, alert and documented recovery path |
| Downstream outage | Event remains durably queued for controlled retry |
| Environment test | Staging cannot update live CRM, stock or fulfilment data |
Retain the event identifier, timestamps, response code and resulting object ID for the test. Remove or clearly label test records. Monitor delivery failures and receiver queue age after release rather than waiting for a customer to report missing fulfilment.
When custom integration work is justified
A direct webhook is appropriate when the receiving system has a stable endpoint and the workflow is small. A custom integration layer becomes valuable when you need transformations, multi-destination routing, replay, deduplication, reconciliation or operational dashboards.
Innovative Code Tech provides custom WordPress and WooCommerce plugin development for scoped webhook and API work. For CRM, ERP or multi-application workflows, review the broader API integration and software services before committing to fragile one-off automation.
Frequently asked questions
Where are WooCommerce webhook logs?
Open WooCommerce → Status → Logs and filter for the webhook delivery source. Use the webhook ID, delivery ID, timestamp and response to correlate with the receiving system.
Why did WooCommerce disable my webhook?
WooCommerce disables webhooks after repeated unsuccessful deliveries. Fix the receiver, certificate, routing or response problem before reactivating and testing it.
How do I verify a WooCommerce webhook?
Compute an HMAC-SHA256 over the exact raw request body using the stored secret, Base64-encode it and compare it safely with the X-WC-Webhook-Signature header.
Can WooCommerce send the same webhook more than once?
Your integration should assume duplicates are possible because of retries, timeouts or manual recovery. Make processing idempotent with a durable unique event or business-operation key.
Should the webhook receiver finish all work before responding?
Usually no. Verify and durably record or enqueue the event, then acknowledge quickly. Complete slower downstream work asynchronously with monitoring and retry controls.
Treat delivery as a system, not a checkbox
Reliable WooCommerce webhooks need more than an active status and a URL. Define the event contract, verify the signature, accept events durably, prevent duplicate effects, monitor both delivery and downstream processing, and test failure recovery before live orders depend on the integration.