From 62dd05780a7cadbc94b7cc4bae2aeddf72b01fc6 Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Wed, 3 Jun 2026 06:13:22 +0000 Subject: [PATCH] Add payment_status guard to payment_intent.succeeded handler Mirrors the checkout.session.completed case which checks payment_status === paid before acting. Now checks data.status === succeeded on the PaymentIntent object, consistent with how Stripe structures the event and defensive against any future edge case where the event fires in a non-final state. --- api/webhook.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/webhook.php b/api/webhook.php index bc875b6..beb9113 100644 --- a/api/webhook.php +++ b/api/webhook.php @@ -61,7 +61,7 @@ switch ($eventType) { // Payment Intent flow (embedded/direct) - skip if already confirmed by checkout.session.completed $paymentIntentId = $data['id'] ?? ''; $orderId = $data['metadata']['order_id'] ?? ''; - if ($orderId) { + if ($orderId && ($data['status'] ?? '') === 'succeeded') { $order = db()->fetch("SELECT * FROM orders WHERE order_id = :id", ['id' => $orderId]); if ($order && $order['order_status'] !== 'confirmed') { db()->update('orders',