Synthetic Industry

Troubleshooting guide · updated 2026-10-11

WooCommerce orders stuck on Pending payment after the customer paid: where the confirmation is lost

How a payment confirmation reaches WooCommerce, the status each failure leaves, and a safe way to find where it stops without touching live payments.

What each status tells you

WooCommerce's order statuses are a short story about what the store knows. Pending payment means the order exists but no payment has arrived. Processing means the order is paid and stock has been deducted. On hold means payment is not yet confirmed, although stock is already deducted; that is expected for offline methods and delayed-notification methods. Failed means the payment was declined or did not go through, and stock goes back. So an order that stays Pending payment, or sits On hold for a method that should confirm within minutes, tells you the store has not heard what happened to the money.

There is a further consequence. With the Hold Stock setting enabled, WooCommerce cancels eligible Pending payment orders created through checkout once the time limit passes. If the confirmation never arrived, a customer who did pay can end up with a cancelled order. That is why the delay matters, and why a list of paid-but-pending orders is worth building quickly.

  • Pending payment: the store has no payment yet.
  • On hold: not confirmed, stock reserved.
  • Cancelled by Hold Stock: a risk for paid orders whose confirmation was lost.

How the confirmation travels

For many payment methods the customer is sent away to pay and returns to the store, but the reliable signal comes separately, from the payment provider to the store, as a webhook. The WooCommerce Stripe extension states it directly: it sends requests to Stripe through the API, but Stripe can only reach the extension through webhooks. If that second path is broken, payments succeed at Stripe while the order never changes. The extension's endpoint carries a wc-api route on your site address, and from version 8.6.1 the webhooks are created automatically when the extension connects.

Other gateways differ in detail but follow the same pattern: a notification from the provider to an address on your site, and a status change in WooCommerce when it arrives. If your gateway is not Stripe, read its documentation for the equivalent.

Where the confirmation can be lost

Stripe's documentation gives a table of what a failed delivery looks like, and each row maps to a cause on the store side. Redirects count as failures, so an address that redirects from the bare domain to the www version, or from http to https, fails every time. Access restrictions and missing URLs appear as 4xx statuses, which is how a security plugin, firewall rule or password-protected staging site shows up. Connection and TLS errors point at the host or the certificate, and a timeout means the site was too slow to answer. Stripe expects a quick 2xx before any heavy work.

Anything that changes the site's address, such as a domain change, a move to https or a copy of the site, can leave the provider pointing at the old address. Deleting the webhook in the provider dashboard has the same effect.

  • Redirects on the webhook address count as failures.
  • 4xx statuses point at access rules; connection and TLS errors point at the host or certificate.
  • A changed address leaves the provider calling the old one.

A safe first investigation without touching live payments

Do not retest with a real card. Use the provider's own delivery log, which shows each delivery and the status the store returned, and compare payments with orders for one day by order number and amount only.

  • In the provider dashboard, open the delivery list and note the status code and time on recent entries.
  • For the WooCommerce Stripe extension, check that both the Live and Test tabs show Configured.
  • List payments that succeeded and find their orders; mark any still Pending payment or On hold.
  • Ask what changed before it started: domain, https, host, security plugin, caching or a site copy.
  • Never put keys or signing secrets in an email or screenshot.

What fixes it, and what does not fit

Fixes are usually small and on the store side: make the webhook address answer directly without a redirect, let the provider through a security rule, or recreate the webhooks from the extension's settings. Stripe can resend events from its dashboard for up to 15 days, and a manual resend does not stop its automatic retries, so resending is a recovery step once the cause is fixed. If the payment itself fails at checkout, or the method is meant to wait for manual confirmation, this is a different problem. Refunds, disputes and reconciling money with the provider are yours to handle under your own account.

How the paid fix is accepted

The fixed job for this problem is accepted on a staging copy reachable over HTTPS with the gateway in test mode. A successful test payment moves the order to the agreed status and reduces stock once, the provider's delivery log shows the event delivered with a success status, a declined test payment leaves no paid order, and a second delivery of the same event changes nothing. You or your host make any dashboard or firewall change; we never see live keys or signing secrets.

Sources and limits

  • WooCommerce documentation: Order statuses Checked 2026-10-11.
    • Pending payment means the order exists but no payment has arrived; Processing means paid with stock deducted; On hold means payment is not yet confirmed though stock is deducted.
    • Failed and Cancelled orders return stock to inventory.
    • With the Hold Stock setting enabled, WooCommerce cancels eligible Pending payment orders created through checkout once the configured time limit passes.
  • WooCommerce Stripe extension: Setting up webhooks Checked 2026-10-11.
    • The Stripe extension sends requests to Stripe through its API, but Stripe can only reach the extension through webhooks.
    • The extension uses endpoints of the form the site address followed by a query for the wc-api wc_stripe route.
    • From version 8.6.1 webhooks are created automatically when the extension connects to Stripe, and they can be recreated with a Reconfigure webhooks action on the Live and Test tabs.
    • Both tabs should show the status Configured, and the account details show whether webhooks are being processed successfully.
  • Stripe documentation: Receive Stripe events in your webhook endpoint Checked 2026-10-11.
    • A webhook endpoint must quickly return a 2xx status before complex logic.
    • Stripe treats redirect responses as failures, and access restrictions or a missing URL appear as 4xx statuses.
    • In live mode Stripe attempts delivery for up to three days with exponential back off, and in a sandbox it retries three times over a few hours.
    • The Event deliveries tab lists events as Delivered, Pending or Failed with the HTTP status code.
    • Events can be resent from the Dashboard for up to 15 days, and a manual resend does not cancel automatic retries.
    • Duplicate deliveries should be identified by event ID, and ordering is not guaranteed.