'How to prevent shopping cart alterations when payments are asynchronous
The steps below illustrate my problem with Stripe's PaymentIntent flow, but you could come up with something similar for the other payment gateways I've looked at where the final notification of a successful payment is sent asynchronously from the payment gateway to the merchant site.
- Customer adds 10 x item A to their shopping cart, total now $100
- Customer goes to checkout page. Server creates a Stripe PaymentIntent for the $100 total and sends the 'client_secret' to the browser.
- Customer's browser displays the checkout page, showing $100 total, and Stripe's payment form.
- Customer opens a new tab, and adds 10 x item B to their shopping cart, total now $200.
- Customer returns to checkout tab, and completes $100 payment with Stripe (nothing the site can do to prevent this - it's all happening client side)
- Asynchronously, Stripe notifies the site via webhooks that we've got a $100 payment. What do we do now?
The payment total no longer matches the cart total. Do we have to refund the payment and cancel the order? How do we notify the customer? We've probably already shown them an 'order complete - thank you' page, because we had no way of knowing the total was wrong until the asynchronous notification arrived. The customer's probably left our site already. What do we do with their shopping cart?
-- Some further background to all this:
I used to always turn to Stripe whenever my clients wanted to take online payments on their websites, because Stripe's synchronous model made my code nice and easy. The customer would enter their card details, Stripe would then return a token representing the payment, finally my server side code would check all the details were correct, use Stripe's API to collect the money, and return a 'thank you' message to the customer's browser.
But now it seems Stripe are moving away from this model to an asynchronous model (PaymentIntents), where your server is supposed to listen for notifications for completed payments, before fulfilling orders. In Stripe's terminology, we should set up 'webhooks' listening for the 'payment_intent.succeeded' event.
All the other payment gateways I've used in the past also have an asynchronous model, in the sense that your webserver has to wait for some kind of callback from the gateway notifying us of the payment, before we can safely start processing the order. PayPal calls it 'Instant Payment Notification', Worldpay called it 'Order Webhooks', Adflex called it 'Server2ServerNotification'... etc.
Where I'm struggling, is trying to cope with things that might happen during the gap between checkout starting, and payment notification being received. Given that these payment gateways are all using these kind of asynchronous models, there must be a simple solution to this (and similar) problems, but I'm really stuck - any suggestions would be much appreciated.
Solution 1:[1]
I think the main point you're missing here is that the PaymentIntent amount is set server-side. This means that when your customer opens a new tab and adds more items to their cart, you should be updating the PaymentIntent on your server to reflect the new amount. Then when they switch back to the other tab and complete the payment, you should have the total amount reflected in your PaymentIntent.
Your customer might still see the checkout process for an amount different to what is actually being charged, in which case I suggest you look at implementing websockets to make sure they always see the total amount in their shopping cart.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Paul Asjes |