I have a problem with Stripe Webhooks, especially with payment_intent.processing event. In our old app which I have to maintain we're using 3 payment methods. One of them is SOFORT payment. The main difference of this payment method is that you should wait for the bank response a few days and then get Payment Succeeded response from the Stripe Webhook. But our application requires us to fill the client balance right at the moment when client paid. SOFORT is trustworthy and we never had cases when transaction been cancelled while it'd been processing.
But 2 days ago I faces a new problem when stripe created two payment_intent.processing events with 1 second interval and client got credits on his balance 2 times. Here's a piece of code to explain what I mean:
$paymentIntent = $event->data->object;
$order = Db_Orders::getOrderPaymentIntentId($paymentIntent->id);
switch ($event->type) {
case 'payment_intent.processing':
if ($order['wlo_payment_type'] == PAYMENT_METHOD_SOFORT && $order['wlo_status'] == W_LEADS_ORDER_STATUS_STARTED) Utils::activateOrderOffers($order['id']);
$orderObj = new Db_LeadOrder();
$orderObj->id = $order['id'];
$orderObj->wlo_status = W_LEADS_ORDER_STATUS_PENDING;
$orderObj->save();
break;
case 'payment_intent.succeeded':
if ($order['wlo_payment_type'] != PAYMENT_METHOD_SOFORT && $order['wlo_status'] != W_LEADS_ORDER_STATUS_SUCCESS) Utils::activateOrderOffers($order['id']);
$orderObj = new Db_LeadOrder();
$orderObj->id = $order['id'];
$orderObj->wlo_response_date = Utils::formatDateDb(time());
$orderObj->wlo_status = W_LEADS_ORDER_STATUS_SUCCESS;
$orderObj->save();
break;
default:
echo 'Received unknown event type ' . $event->type;
In activateOrderOffers function I do all the manipulation with client balance. And as you can see in payment_intent.processing event I execute it only for SOFORT payment method with STARTED (initial for all orders) status.
As I understand, in my case I'm listening for two parallel processing events. Am I right and are there any ideas how to solve that? I know, manipulating with balance while payment is not yet succeeded might be a bad practice, but that was the main requirement from the client. Best regards to you all.
Stripe webhook may resend events. According to best practices, you can consider logging events you already received.
https://docs.stripe.com/webhooks#handle-duplicate-events
Webhook endpoints might occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you’ve processed, and then not processing already-logged events.