Reliable WordPress Webhooks: Signatures, Retries and Logs
Build reliable WordPress webhook receivers with signature checks, durable queues, duplicate handling, bounded retries and a practical recovery checklist.

In this article
A webhook connects two systems, but a successful WordPress save does not prove that the other system completed its work. The sender can time out after the receiver has already accepted an event. A receiver can return success before its background worker fails. Those are different failures, and they need different evidence.
This guide focuses on the delivery boundary: accepting an authentic event, preserving it safely and finding out whether it produced the intended result. It complements application-specific integration work without assuming that every sender uses the same headers, retries or signature format.
The examples below are design recommendations, not claims about a client deployment. WooCommerce provides a concrete signature example; a custom WordPress plugin needs its own documented contract.
Write down the delivery contract first
List the event types you accept, the fields that identify the resource, the expected payload version and the sender’s timeout. Record what each response means. If a 200 response means the event has entered a durable queue, say so explicitly; it should not silently mean that an invoice has been sent or a customer record has been created.
An event identifier and a resource identifier serve different purposes. The same order can generate several legitimate updates. Deduplicating every event by order ID would lose later changes. Prefer a sender-provided stable event identity where its semantics are documented, and add a separate business-operation key for actions that must happen once.
Also decide whether an event is a snapshot or a notification to fetch current state. Fetching the resource later can intentionally coalesce several changes, but it cannot reconstruct every intermediate state. Audit trails and notification emails may therefore need a different design from a simple search-index refresh.
Verify signatures on the original bytes
WooCommerce’s default webhook implementation generates a base64-encoded HMAC-SHA256 value from the payload and shared secret, and sends it in X-WC-Webhook-Signature. Verify the exact received body before parsing and reserializing JSON. Reformatting whitespace or changing key order changes the signed bytes even when the parsed object looks equivalent. The WooCommerce implementation is linked below so the algorithm can be checked against the version you run.
Use a constant-time comparison function appropriate to the runtime after decoding and validating the expected signature format. Reject missing or malformed signatures without running business logic. Keep secrets in deployment configuration and avoid putting them in URLs, browser bundles or request logs. A test fixture with a known payload and signature makes accidental middleware changes easier to detect.
A valid signature demonstrates possession of the signing secret; it does not automatically establish freshness. Where the sender signs a timestamp, enforce a documented tolerance. Where it does not, do not invent a timestamp check that the sender cannot satisfy. Use durable duplicate controls and assess the replay risk in the operation itself. Apply request-size limits and accept only the intended methods and content types.
Return success only after durable acceptance
For a receiver you control, perform the minimum trustworthy work in the HTTP request: authenticate, validate the envelope and store a job durably. Return the agreed success response only after storage succeeds. If a database or queue is unavailable, returning success can permanently hide an event from the sender’s recovery process.
A worker can then perform slower operations such as CRM updates or document generation. Store enough context to retry safely: event identity, resource identity, receipt time, payload version and processing state. Protect any personal data in the payload with the same access and retention rules as the destination system.
Acknowledge the difference between queued and completed in your dashboard. A list of successful HTTP deliveries proves only the first stage if processing is asynchronous. A useful operations view includes accepted, processing, completed and needs-attention states, with an explanation of what an operator can safely replay.
Make duplicates harmless at the business boundary
Imagine the receiver accepts an event and the connection closes before the sender receives the response. The sender may deliver again. If the receiver creates an invoice on every request, a network problem becomes a billing problem. This is a hypothetical failure scenario worth reproducing in staging.
Use an atomic database constraint or equivalent operation to claim a deduplication key. A separate read followed by an insert can race when two requests arrive together. Keep the claim and job creation consistent so a failed enqueue does not leave an event permanently marked as processed.
The downstream operation also needs protection. A worker can crash after the remote service creates a record but before the local completion flag is saved. Reuse a supported idempotency key at that service or reconcile against a stable business identifier. A local event table alone cannot guarantee exactly-once effects across independent systems.
Separate retryable failures from broken requests
For custom delivery or worker logic, retry transient connection failures and suitable server errors with bounded exponential backoff and jitter. Respect a valid Retry-After instruction when supported by the destination. Set an attempt limit and an overall age limit so a broken integration does not create an endless background workload.
Authentication failures, unsupported payload versions and validation errors usually need a configuration or data correction. Repeating an unchanged request every minute is unlikely to help. Record a safe reason, alert the responsible person and keep a controlled replay path after the underlying issue is fixed.
Do not assume WooCommerce will replay every missed business event indefinitely. Its webhook implementation tracks consecutive delivery failures and can disable a webhook; the threshold is filterable and behavior should be verified against your installed version. Monitor webhook status and delivery logs. Reactivating a disabled webhook is separate from recovering all changes that occurred during the interruption.
Log a trace without creating a second customer database
Record a correlation ID, event type, resource reference, attempt number, response category and processing duration. Those fields can connect a WordPress delivery to a receiver job and destination result. Keep secrets, authorization headers and full customer messages out of ordinary logs.
For troubleshooting that requires a payload, store it behind restricted access with an explicit retention period. Redact the details that do not help explain the failure. Remember that URLs and error messages can contain sensitive values too; sanitizing only the request body is not sufficient.
Useful alerts answer a concrete question: are jobs getting older, has a webhook become disabled, or are authentication errors increasing after a secret rotation? A single dashboard total called “success” hides too much. Document who receives each alert and what the first diagnostic step should be.
Test failure and recovery before launch
Test a correctly signed event, an altered body, a missing signature, two simultaneous duplicates and an event for an unsupported resource. Then simulate a slow downstream API, a temporary failure and a worker restart after the remote action succeeds. Verify the resulting business state, not only the HTTP status.
Exercise secret rotation with the sender’s supported configuration. Record the change order and any short overlap window you deliberately allow. Avoid permanently accepting every old secret because a migration was never finished. Keep replay tools restricted to operators who understand their effects.
Finally, rehearse reconciliation: compare the authoritative source with the destination over a defined window and repair confirmed gaps. For CRM-specific field mapping and consent handling, read the existing WordPress CRM integration guide. For API design fundamentals, start with the WordPress REST API guide. Reliable delivery is one layer of the integration, not a substitute for correct business rules.
Frequently asked questions
Does a 200 response prove the integration finished?
Only if that is the documented contract. An asynchronous receiver commonly returns success after durable acceptance; a separate processing result must confirm the business action.
Can I verify a signature after parsing JSON?
Preserve the raw request body first. For WooCommerce’s default scheme, verify the HMAC against those original bytes rather than a reserialized object.
Will WooCommerce retry all failed events automatically?
Do not rely on unlimited replay. Delivery failures can disable a webhook. Check the behavior of your installed version, monitor status and use reconciliation to recover confirmed gaps.
How do I prevent duplicate actions?
Combine atomic event deduplication with idempotency or reconciliation at the downstream business operation. Retries can happen after a remote action succeeds but before your worker records completion.
Topics
- WordPress webhook reliability
- WordPress webhook signature verification
- WooCommerce webhook delivery failures