Fixing WooCommerce orders stuck on "Pending payment" or "On hold"
What the WooCommerce "Pending payment" and "On hold" statuses mean, and how to fix orders that stay stuck even though the customer has paid, covering webhooks, gateway settings, firewalls, caching and background processing.
A customer tells you they've paid, the money has shown up in Stripe or PayPal, but the order in WooCommerce is still sitting on Pending payment. Or orders keep landing on On hold and you're not sure whether to ship them. Either way, stock levels, confirmation emails and fulfilment all depend on the status being right, so it needs sorting.
The first thing to know is that both statuses are normal in the right circumstances. The problem is when an order gets stuck in one of them after payment has actually happened.
What the statuses mean
WooCommerce's own documentation defines the statuses like this:1
Pending payment means the order has been received but no payment has been made yet. Every order starts here the moment the customer clicks the order button, and it should move on within seconds once the payment gateway confirms payment.
On hold means the order is awaiting payment confirmation. Stock has been reduced, but you need to confirm the payment. Bank transfer (BACS) and cheque orders go to On hold by design, because you have to check your bank account yourself. Card and PayPal gateways sometimes use it for payments that need review.
Processing means payment has been received, stock has been reduced and the order is waiting to be fulfilled. This is where a successful card order should end up.
Failed means the payment failed or was declined.
Because WooCommerce's order emails are triggered by status changes, an order stuck on Pending payment also means the customer and you don't get the usual emails. Our guide to WooCommerce order emails not sending explains how the two are linked.
Pending orders that were never paid
Before chasing a technical fault, check whether the customer actually completed payment. Plenty of pending orders are simply abandoned checkouts: the customer reached the payment step, then closed the tab, had their card declined or got distracted.
Open the order and read the Order notes on the right-hand side. Most gateways add notes as they go, recording each step of the payment. Then search for the order in your payment provider's dashboard.
If there's no successful payment on the provider's side, the order is genuinely unpaid. WooCommerce's Hold stock (minutes) setting, under WooCommerce → Settings → Products → Inventory, cancels pending orders automatically once the time limit passes and releases their stock.2 If you're seeing large numbers of unpaid pending orders from strangers, you may be the target of card testing. See our guide to preventing spam and fraudulent orders.
Paid orders stuck on Pending: check webhooks
If the payment definitely succeeded but the order is still pending, the gateway's confirmation hasn't reached WooCommerce. Modern gateways such as Stripe and PayPal confirm payments by sending a message called a webhook directly from their servers to yours. If that message is blocked or rejected, WooCommerce never hears that the payment went through.
For Stripe, the official WooCommerce Stripe extension has set webhooks up automatically when you connect your account since version 8.6.1. To check them, go to WooCommerce → Settings → Payments → Stripe → Settings and click Configure connection. The webhook status should say it's configured. If webhooks were deleted, or you connected before 8.6.1, the Reconfigure webhooks button recreates them.3 On the Stripe side, open the Webhooks tab in Stripe's Workbench, select your endpoint and look at the Event deliveries tab. Each delivery shows whether it was delivered or failed, and the HTTP response your site gave.4
For PayPal, the WooCommerce PayPal Payments plugin sets up webhooks during onboarding. Its settings include a Webhook Status section with a Resubscribe button, which refreshes the webhooks, and a Simulate button, which tests that your site receives them.5
Common reasons webhooks fail:
- A firewall or security plugin is blocking the incoming request because it doesn't come from a browser. Check your security plugin's logs, your host's firewall and Cloudflare's security events for blocked requests from the gateway. The same culprits cause many 403 forbidden errors.
- Maintenance or "coming soon" mode is returning a holding page to every visitor, including the gateway's servers.
- Test and live settings are mixed up, for example after switching modes or regenerating API keys, so the webhook can't be verified.
- The webhook points at the wrong address, for example an old domain, a staging site or
http://instead ofhttps://. If you've recently moved the site to HTTPS, our guide to fixing mixed content covers the other places old URLs hide. - The site is throwing an error when processing the webhook. Check WooCommerce → Status → Logs for gateway logs and fatal errors around the time of the order.
Once you've fixed the cause, Stripe keeps retrying failed deliveries automatically for up to three days in live mode, and you can resend individual events from the event deliveries list.4 Affected orders should then move to Processing by themselves.
Check test and live mode settings
A mismatch between modes causes confusing behaviour. If WooCommerce is using live API keys but webhooks are configured on the test account (or the other way round), payments go through but confirmations never arrive.
In your gateway settings, confirm that test or sandbox mode is off and that the live connection is active. The Stripe extension shows separate Live and Test tabs under Configure connection, each with its own webhook status.3
Rule out caching on checkout pages
The checkout, cart, My Account and order received pages must never be cached. If they are, the customer may see an old or wrong version of the page and the gateway's return process can fail, leaving the order pending.
Most caching plugins exclude these pages automatically, but custom rules, host-level caching and CDN rules such as Cloudflare's "Cache Everything" often don't. Check that /checkout/, /cart/, /my-account/ and anything containing order-received are excluded everywhere. Our guide to fixing WooCommerce checkout problems covers other ways caching breaks checkout.
Check background processing
Some gateways and plugins don't update the order status straight away. They schedule a background task to do it, using WooCommerce's Action Scheduler. If scheduled tasks aren't running, those updates never happen.
Go to WooCommerce → Status → Scheduled Actions and look at the Past-due and Failed lists. A long list of past-due actions, especially ones related to your payment gateway or order processing, points at this problem. Our guide to fixing past-due and failed scheduled actions covers how to get the queue moving again.
Orders going to On hold unexpectedly
If card or PayPal orders are landing on On hold rather than Processing, the order notes usually explain why. Common reasons include:
- PayPal is holding the payment on its side, for example when it's flagged for review or needs accepting manually in your PayPal account. Check the transaction in PayPal.
- Your fraud rules are holding it for review. Stripe Radar and some anti-fraud plugins can place risky orders on hold for you to check.
- A bank payment is still clearing. Some payment methods take several working days to confirm.
- A plugin is changing the status. Some plugins set orders to On hold deliberately, for example for pre-orders, B2B approval or manual stock checks.
For bank transfer orders, On hold is expected. Once the money appears in your bank account, change the order to Processing and WooCommerce will email the customer.
Fixing orders that are already stuck
For each stuck order, confirm the payment in your provider's dashboard. If it's genuinely paid, and resending the webhook isn't possible, change the order status to Processing manually and click Update.
Changing the status triggers the same things a gateway confirmation would, including stock changes and customer emails, and those can't be taken back. So double-check you've got the right order before saving. Add a private order note recording what you checked, such as the payment ID from your provider. It'll save time if there's ever a query or a refund later.
Still stuck?
If orders keep getting stuck after checking webhooks, firewalls and caching, enable debug logging in your gateway's settings and place a test order. The gateway log in WooCommerce → Status → Logs will usually show exactly where the process stops. Switch debug logging off again afterwards. If you need help reading the logs or fixing the underlying problem, my WordPress development service and emergency WordPress support cover WooCommerce payment gateways, webhook failures and checkout problems.
Order statuses, WooCommerce. ↩
Products settings, WooCommerce. ↩
Setting up webhooks, WooCommerce Stripe extension documentation. ↩ ↩
Receive Stripe events in your webhook endpoint, Stripe Docs. ↩ ↩
WooCommerce PayPal Payments troubleshooting, WooCommerce. ↩