Forum Replies Created

Viewing 2 replies - 1 through 2 (of 2 total)
  • Stripe’s diagnosis is exactly right, and I can point to the exact code path that causes it. The Checkout Session flow (Adaptive Pricing / Elements ui_mode) is built by WC_Stripe_Checkout_Sessions_Ajax_Handler::create_checkout_session(), and its payment_intent_data comes from build_payment_intent_data() — which only ever sets metadata. It never calls WC_Stripe_Helper::get_payment_intent_description( $order ), which is the plugin’s own helper that produces the “{blog name} – Order {number}” string you saw on the working payments. That helper is used by the classic direct-PaymentIntent flow elsewhere in the plugin, just not by this one.

    So it’s not intermittent in the sense of a race condition — it’s fully deterministic per code path: any payment that goes through the Checkout Sessions ajax handler will never carry a description, full stop. Whether a given order hits that handler depends on which checkout flow initiated it, which is worth confirming on your end — if you’re running Adaptive Pricing / multi-currency Stripe checkout, that’s the flow, and every payment through it will show this gap. If some other flow is also missing the description, that would be a second, separate spot to find.

    Two ways to close it, since payment_intent_data isn’t filterable in that specific request array today:

    1. File it as a bug against woocommerce/woocommerce-gateway-stripe on GitHub — the fix is a one-line addition (‘description’ => WC_Stripe_Helper::get_payment_intent_description( $order )) inside build_payment_intent_data(), but there’s no hook wired into that array yet for a site-side patch to reach it without a custom fork of the handler.

    2. Workaround in the meantime: metadata (unlike description) *is* set reliably in both flows, including site_url. If your Stripe email templates or any downstream reconciliation script can key off metadata instead of the description field, you get the order association back without waiting on upstream.

    One question that would confirm which orders are affected: are you running Adaptive Pricing / a multi-currency Stripe checkout, or a different Elements/block checkout? That tells you whether this is universal for your store or only a subset.

    Razorpay support’s advice (enable order.paid and payment.captured in your webhook config) won’t fix this — the official razorpay-woocommerce plugin doesn’t listen for either event. I checked the plugin source (includes/razorpay-webhook.php): the switch only has cases for payment.authorized, payment.failed, payment.pending, virtual_account.credited, refund and subscription events. order.paid and payment.captured aren’t consumed anywhere in the codebase.

    What the plugin actually reacts to is payment.authorized. Its handler (paymentAuthorized()) does this: fetch the payment entity; if status === ‘captured’, mark the order paid; if status === ‘authorized’ and your gateway setting payment_action is capture (your “Authorize and Capture” mode), the plugin itself calls $payment->capture() and then marks the order paid. Either way, the order transition is gated entirely on receiving that one event.

    So the first thing to check isn’t the two events Razorpay named — it’s whether payment.authorized is checked in your webhook’s event list, and whether its delivery log at Razorpay’s end shows a 200 response reaching your site for those orders (not a timeout, not a 403 from a security plugin/WAF on the callback URL).

    Separately: is this every order, or intermittent? If intermittent, it’s worth knowing whether capture is happening fast enough that Razorpay ever gets to fire payment.authorized before payment.captured, or whether it’s a delivery problem (retries exhausted, wp-cron delayed on a low-traffic install).

    Structural note either way: this plugin has no reconciliation path. If that one webhook is dropped for any reason — network blip, WAF, wp-cron backlog — the order sits Pending forever even though the money is captured, and nothing on the WooCommerce side ever re-checks. A small scheduled job that polls Razorpay’s Payments API for orders still Pending after, say, 15 minutes and reconciles their status would close that gap regardless of which webhook misfires next time.

Viewing 2 replies - 1 through 2 (of 2 total)