WooCommerce order stuck on "pending payment" after a successful Stripe charge? It's a missed webhook

Stripe says the payment succeeded and the money is in your balance — but the WooCommerce order is still sitting on "Pending payment". Stock wasn't reduced, no receipt went out, and the customer is confused. This is one of the most-reported WooCommerce + Stripe issues, and it has a specific cause. Here's what's happening, how to check it, how to fix a stuck order safely, and how to stop it silently costing you sales.

Short version: Stripe captured the payment and sent a payment_intent.succeeded webhook to your site — but that event never arrived or wasn't processed (firewall, timeout, a 204/cached response, or a failed scheduled action). So the money side and the store side disagree. Verify the order actually paid in Stripe, then complete it. To stop the silent revenue loss, you need something that re-queries the gateway and reconciles the ones that were really paid.

Why the order is stuck

WooCommerce and Stripe stay in sync through webhooks: when a payment completes, Stripe sends an event to a URL on your site, and the Stripe gateway updates the order. If that message fails to arrive or process, the order never leaves "pending". Common causes, all documented in the wild:

The pattern is well known — see the open WooCommerce core issue #66175 ("Stripe succeeding, order stuck, webhook 204, never updates") and the Stripe-gateway issue #3154 ("URGENT: paid orders stuck at pending").

How to check what happened

  1. Stripe dashboard: find the PaymentIntent for the order — did it actually reach succeeded? Note the transaction / charge ID.
  2. Stripe → Developers → Webhooks: check recent deliveries to your site. Failed or non-200 responses point straight at the cause.
  3. WooCommerce → Status → Scheduled Actions: filter for failed/pending actions around the affected order IDs.
  4. WooCommerce → Status → Logs: the Stripe log shows whether payment_intent.succeeded was received and processed.

How to safely fix a stuck order

Once you've confirmed in Stripe that a specific order was paid (succeeded + a real transaction ID), mark it Processing/Completed in WooCommerce so stock, receipts and integrations fire. If your gateway offers an order action to "sync/authorize from Stripe", use that — it completes the order the correct way rather than just flipping a status.

⚠️ Never bulk-complete pending orders. Some genuinely weren't paid (abandoned, failed, or awaiting an async method). Completing those means fulfilling without payment. Every order must be checked against the gateway's PAID status and transaction ID first.

Stop the silent revenue loss

Fixing webhook delivery helps, but webhooks are structurally unreliable — firewalls, timeouts, live/test key mix-ups and 204s will always leak some events. Checking every pending order by hand doesn't scale, and each missed one is real money you already earned sitting invisible.

● Launching soon on WordPress.org

Let PaidRadar recover them automatically

PaidRadar — the sibling tool to PayDrift in the famosMedia Payment-Integrity family — scans your pending / on-hold / failed orders, re-queries the gateway (Stripe, PayPal) read-only, and for the ones that actually succeeded it completes them correctly via payment_complete() — with a full audit trail. Conservative by default: it only completes an order on a confirmed PAID status with a transaction ID, and never touches unpaid or refunded ones. Self-hosted, no cloud.

Get notified when PaidRadar launches

FAQ

Why is the order pending when Stripe says it succeeded?

The webhook that tells WooCommerce the payment completed didn't arrive or process — blocked, timed out, returned a 204, or a scheduled action failed. The money is in Stripe but the store never got the message.

How do I fix one stuck order?

Confirm the PaymentIntent succeeded in Stripe and note the transaction ID, then mark that order Processing/Completed (or use the gateway's sync action). Only for confirmed-paid orders.

Can I just mark all pending orders as paid?

No — some weren't paid. Each must be verified against the gateway's PAID status and transaction ID first, or you'll ship without payment.

How do I stop it happening?

Fix webhook delivery (firewall/cache/scheduled actions), and because webhooks always leak some events, use a tool that re-queries the gateway and reconciles the truly-paid orders — that's what PaidRadar does.

Related: catching silent payment-config changes with PayDrift →