<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: moxianyu6975-cpu</title>
    <description>The latest articles on DEV Community by moxianyu6975-cpu (@moxianyu6975cpu).</description>
    <link>https://dev.to/moxianyu6975cpu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4084768%2F8860e78a-3a03-4527-8fc7-97185200aeac.png</url>
      <title>DEV Community: moxianyu6975-cpu</title>
      <link>https://dev.to/moxianyu6975cpu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moxianyu6975cpu"/>
    <language>en</language>
    <item>
      <title>Stripe Says Paid, WooCommerce Says Pending: A Safe Reconciliation Checklist</title>
      <dc:creator>moxianyu6975-cpu</dc:creator>
      <pubDate>Wed, 19 Aug 2026 11:26:08 +0000</pubDate>
      <link>https://dev.to/moxianyu6975cpu/stripe-says-paid-woocommerce-says-pending-a-safe-reconciliation-checklist-nml</link>
      <guid>https://dev.to/moxianyu6975cpu/stripe-says-paid-woocommerce-says-pending-a-safe-reconciliation-checklist-nml</guid>
      <description>&lt;p&gt;A customer completes checkout. Stripe shows a successful payment, but the WooCommerce order is still &lt;strong&gt;Pending payment&lt;/strong&gt;, &lt;strong&gt;On hold&lt;/strong&gt;, or &lt;strong&gt;Failed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The tempting response is to change the order status immediately. That can create a second problem: fulfillment may begin before you have confirmed the exact payment, amount, currency, refund state, and customer order.&lt;/p&gt;

&lt;p&gt;This checklist keeps diagnosis separate from state-changing actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  First: treat both systems as evidence
&lt;/h2&gt;

&lt;p&gt;Neither a WooCommerce status label nor a Stripe dashboard row tells the whole story on its own.&lt;/p&gt;

&lt;p&gt;Before changing anything, record:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the WooCommerce order status and timestamps;&lt;/li&gt;
&lt;li&gt;the exact Stripe PaymentIntent or charge reference stored on the order;&lt;/li&gt;
&lt;li&gt;the Stripe object's current status;&lt;/li&gt;
&lt;li&gt;gross amount and currency in both systems;&lt;/li&gt;
&lt;li&gt;refunded total in both systems;&lt;/li&gt;
&lt;li&gt;relevant WooCommerce order notes;&lt;/li&gt;
&lt;li&gt;Stripe event and webhook-delivery timestamps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not paste customer data, card data, API keys, webhook secrets, or full payment identifiers into a public support thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Confirm that you are comparing the same payment
&lt;/h2&gt;

&lt;p&gt;A status comparison is useful only when both records refer to the same transaction.&lt;/p&gt;

&lt;p&gt;Check that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the Stripe object ID on the order resolves to the object you are viewing;&lt;/li&gt;
&lt;li&gt;the WooCommerce gateway and the Stripe object use the same test or live mode;&lt;/li&gt;
&lt;li&gt;the store is connected to the same Stripe account that originally created the payment;&lt;/li&gt;
&lt;li&gt;a retry or a second checkout attempt did not create a newer PaymentIntent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the reference is missing or points to another account or mode, stop there. The provider read is not authoritative for that order until the identity problem is resolved.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Allow for asynchronous updates
&lt;/h2&gt;

&lt;p&gt;WooCommerce payment updates are not always synchronous with the browser returning from checkout. Webhooks, redirects, background actions, and retries can complete at different times.&lt;/p&gt;

&lt;p&gt;Use a short grace period before calling a status difference an incident. Five minutes is a practical starting point for an automated comparison, but your payment methods and checkout flow may need a different threshold.&lt;/p&gt;

&lt;p&gt;The goal is to avoid alerting on a normal, temporary transition while still catching an order that remains inconsistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Inspect the full webhook path
&lt;/h2&gt;

&lt;p&gt;In Stripe, find the event related to the exact PaymentIntent or charge and review its delivery history.&lt;/p&gt;

&lt;p&gt;Then check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether Stripe sent the event to the expected endpoint;&lt;/li&gt;
&lt;li&gt;the response code and response time;&lt;/li&gt;
&lt;li&gt;whether a retry later succeeded;&lt;/li&gt;
&lt;li&gt;whether a proxy, WAF, cache, maintenance mode, or security rule could intercept the request;&lt;/li&gt;
&lt;li&gt;the WooCommerce Stripe logs at the same timestamp;&lt;/li&gt;
&lt;li&gt;PHP and server logs for an exception after the endpoint accepted the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An HTTP 2xx response is useful evidence, but it does not by itself prove that every downstream order update finished successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Compare normalized financial values
&lt;/h2&gt;

&lt;p&gt;Do not compare formatted strings such as &lt;code&gt;$149.00&lt;/code&gt; and &lt;code&gt;149&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Normalize the values first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;convert the WooCommerce order total to the currency's smallest unit;&lt;/li&gt;
&lt;li&gt;compare it with the authoritative Stripe amount for the exact object;&lt;/li&gt;
&lt;li&gt;compare lowercase ISO currency codes;&lt;/li&gt;
&lt;li&gt;compare the total refunded amount only when the Stripe response provides authoritative refund data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Amount and currency differences deserve immediate investigation. They do not automatically prove that Stripe charged the wrong amount; manual edits, unusual capture flows, retries, and integration failures can also produce data drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Distinguish the common disagreement patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Stripe succeeded; WooCommerce remains unpaid
&lt;/h3&gt;

&lt;p&gt;Verify the exact successful provider object, then inspect order notes, webhook delivery, gateway logs, and any exception between webhook receipt and the order-status write.&lt;/p&gt;

&lt;h3&gt;
  
  
  WooCommerce says paid; Stripe reports a terminal failure
&lt;/h3&gt;

&lt;p&gt;Look for a later retry or a replacement PaymentIntent before concluding that the order is unpaid. A stale reference can make a correct order look wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refund totals differ
&lt;/h3&gt;

&lt;p&gt;Confirm whether the refund happened in WooCommerce, directly in Stripe, or through another integration. Check partial refunds and whether both systems have processed the latest update.&lt;/p&gt;

&lt;h3&gt;
  
  
  No usable Stripe reference
&lt;/h3&gt;

&lt;p&gt;Treat this as an identity problem, not a payment-status conclusion. Investigate how the order was created and whether another gateway or extension stores identifiers differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Automate comparison, not remediation
&lt;/h2&gt;

&lt;p&gt;A safe monitor can run a bounded, read-only scan over recent Stripe orders and report:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;status disagreements after a grace period;&lt;/li&gt;
&lt;li&gt;gross amount or currency mismatches;&lt;/li&gt;
&lt;li&gt;refund-total mismatches;&lt;/li&gt;
&lt;li&gt;stale pending orders;&lt;/li&gt;
&lt;li&gt;missing or unreadable Stripe references.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep the first version read-only. Automatically changing order state, replaying webhooks, capturing funds, or issuing refunds turns a visibility tool into a financial-action system with a much larger failure surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Decide the action only after identifying the cause
&lt;/h2&gt;

&lt;p&gt;A mismatch is a prompt to investigate, not a repair instruction.&lt;/p&gt;

&lt;p&gt;Before fulfillment or a financial change, confirm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which exact payment belongs to the order;&lt;/li&gt;
&lt;li&gt;whether the customer was charged and for what amount;&lt;/li&gt;
&lt;li&gt;whether a newer event or retry exists;&lt;/li&gt;
&lt;li&gt;whether the order notes and logs support the intended state;&lt;/li&gt;
&lt;li&gt;whether another integration will repeat or reverse your manual action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Document the evidence and the action taken so the next incident is easier to diagnose.&lt;/p&gt;

&lt;h2&gt;
  
  
  A free read-only implementation
&lt;/h2&gt;

&lt;p&gt;Disclosure: I maintain &lt;a href="https://wordpress.org/plugins/payment-truth-for-woocommerce/" rel="noopener noreferrer"&gt;Payment Truth for WooCommerce&lt;/a&gt;, a GPL-licensed plugin that implements this bounded comparison for stores using the official WooCommerce Stripe Gateway. It uses the gateway's existing connection, stores no additional Stripe secret key, and never moves money or changes an order.&lt;/p&gt;

&lt;p&gt;We are currently looking for five store owners, maintainers, or agencies to run one privacy-safe scan and share candid feedback, including healthy or empty results. The &lt;a href="https://moxianyu6975-cpu.github.io/payment-truth-for-woocommerce/real-store-validation/" rel="noopener noreferrer"&gt;ten-minute validation steps&lt;/a&gt; explain exactly what to share and what never to post publicly.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>wordpress</category>
      <category>woocommerce</category>
      <category>stripe</category>
    </item>
  </channel>
</rss>
