A WooCommerce webhook is a message your store sends to another service when something happens, such as an order being created or updated. You set it up once under WooCommerce, Settings, Advanced, Webhooks: you choose the event (the topic), the address it goes to (the delivery URL) and a secret used to sign each message. From then on WooCommerce delivers the order to that address every time the event fires. Most problems come from four places: the wrong topic, a secret that differs on each side, a webhook with no user allowed to read orders, and deliveries that are paused or delayed.
This guide explains each field in plain words, then goes through those errors.
What a webhook is, in store terms
Think of it as an automatic email between two systems. Instead of a person checking your orders and copying them somewhere, WooCommerce sends each order to a service the moment it changes. The service might be an accounting tool, a fulfilment partner or a sales notification widget.
Two things make this better than copying data by hand or by a nightly export:
- It is immediate. The receiving service hears about an order within moments.
- It can be checked. With a secret, the receiver can prove the message came from your store and was not altered on the way.
The fields on the webhook screen
| Field |
What it means |
What to put |
| Name |
A label for you |
Something that says where it goes, such as "Orders to Provedly" |
| Status |
Active, Paused or Disabled |
Active, once you are ready |
| Topic |
Which event triggers a delivery |
Usually an order topic, see below |
| Delivery URL |
Where WooCommerce sends the message |
The address the receiving service gives you, starting with https |
| Secret |
A shared value used to sign each message |
A long value you also paste into the receiving service |
| API version |
The format of the message |
The current WP REST API version, unless the service says otherwise |
There is one setting you do not see as a field but which matters a lot: every webhook belongs to a WordPress user. WooCommerce builds each delivery by reading the order through its own REST API as that user. If the user cannot read orders, the delivery contains an error instead of the order.
order.created or order.updated
These two topics are where most setups go wrong.
- order.created fires once, when the order is first saved. For many payment methods that happens before the customer has paid, so the order may still be Pending payment.
- order.updated fires every time the order changes: when the payment goes through and the status moves to Processing, when you mark it Completed, when you add a note.
If you want to act on paid orders only, order.created alone can miss the moment of payment, and it can deliver orders that are never paid. order.updated sees the payment, but it also sends the same order several times. The usual answer is to listen to order.updated and have the receiving service do two things: ignore orders whose status is not paid, and remember which order ids it has already handled.
That is exactly what Provedly does with WooCommerce. It records an order only when its status is Processing or Completed, and records each order id once, however many updates arrive. It accepts order.created deliveries too, with the same rules.
The secret and the signature
When a webhook has a secret, WooCommerce runs the message body and the secret through a hashing function (HMAC-SHA256) and sends the result in a header called X-WC-Webhook-Signature. The receiving service does the same calculation with its copy of the secret. If the two results match, the message came from someone who knows the secret and was not changed on the way. If they differ, the service should throw the message away.
Practical points:
- The secret must be identical on both sides, including capital letters and no extra spaces.
- Choose a long, random value, and keep it out of screenshots and support tickets.
- Changing it on one side breaks deliveries until you change it on the other.
The signature is what lets a sales notification honestly say "Verified purchase". Without it, anyone who learned the delivery URL could send a made-up order. Our explainer on webhook signing secrets compares how Stripe, Shopify and WooCommerce do it.
Common errors and fixes
| What you see |
Cause |
Fix |
| The receiving service gets a REST API error instead of the order, often about permissions |
The webhook's user cannot read orders, or the webhook was created by a script with no user |
Make sure an administrator owns the webhook. The Provedly plugin assigns one when it creates the webhook |
| "Invalid signature" in the delivery log |
The secrets differ |
Paste the same secret on both sides |
| Nothing arrives at all |
The webhook is Paused or Disabled, or the delivery URL has a typo |
Set it to Active and copy the URL again |
| The webhook switched itself to Disabled |
WooCommerce disables a webhook after repeated failed deliveries |
Fix the cause, then set it back to Active |
| Orders arrive minutes late |
Deliveries are queued as background jobs that run when the site gets traffic or a scheduled task |
Check WooCommerce, Status, Scheduled Actions for pending webhook jobs |
| Unpaid orders show up in another tool |
The topic is order.created and the tool does not check status |
Use order.updated, and filter by status |
WooCommerce keeps a log of deliveries under WooCommerce, Status, Logs. It shows the response the receiving service sent back, which is usually the fastest way to see what went wrong.
When you create a new webhook, WooCommerce sends a short test "ping" to the delivery URL. A well-built receiver answers it so the webhook can activate; it does not contain an order.
Doing this with Provedly
You do not have to set any of this up by hand. The free Provedly plugin creates the webhook when you paste the delivery URL and secret on its settings page and click Save: topic order.updated, current API version, active, signed with your secret, owned by an administrator. Our guide to WooCommerce recent sales notifications walks through the setup.
Frequently asked questions
Do I need a secret on my WooCommerce webhook?
Not for WooCommerce to send it, but you should always set one when the receiver supports it. Without it, the receiver cannot tell your store's messages from anyone else's, and a sales notification built on unsigned messages cannot honestly be called verified.
Can I have more than one webhook for orders?
Yes. Each service gets its own webhook with its own delivery URL and secret. They do not interfere with each other, and pausing one leaves the others running.
Will a new webhook send my past orders?
No. A webhook fires on events that happen after it exists, so older orders are only sent if they change, for example when you mark one Completed. To bring in history, use the receiving service's import option instead.
Connect your WooCommerce orders over a signed webhook on Provedly's free plan by creating an account.