-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Open
Description
Bug
The Stripe adapter's confirmOrder handler in @payloadcms/plugin-ecommerce retrieves the PaymentIntent but never checks paymentIntent.status before creating an order. This means a failed or canceled payment (e.g. PayPal test failure) still results in:
- An order document being created
- The cart marked as purchased (
purchasedAt) - The transaction set to
succeeded
Source
The PaymentIntent is retrieved at line 48 but its status is never checked before proceeding to create an order at line 58.
Reproduction
- Set up the ecommerce plugin with Stripe (PayPal enabled)
- Create a cart and initiate payment
- On Stripe's PayPal test page, click "Fail payment"
- Stripe redirects back to the
return_urlwithredirect_status=failed - The client calls
/api/payments/stripe/confirm-order - An order is created in the CMS despite the payment having failed
Expected Behavior
confirmOrder should verify paymentIntent.status === 'succeeded' before creating an order. For any other status, it should return an error.
Suggested Fix
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentID)
+
+if (paymentIntent.status !== 'succeeded') {
+ throw new Error(`Payment not completed. Status: ${paymentIntent.status}`)
+}
+
const cartID = paymentIntent.metadata.cartIDStripe Documentation
Stripe explicitly recommends verifying payment status server-side before fulfillment:
"Do not attempt to handle order fulfillment on the client side, as customers may leave the page after payment completes but before fulfillment begins."
Reactions are currently unavailable