I’m creating a my stripe Payment Intent as follows using PHP.
if($params['payment_method'] == 'stripe') {
$paymentIntent = $stripe->paymentIntents->create([
'shipping' => [
"name" => $uModel->full_name,
"phone" => $params['billing_phone'],
"address" => [
"city" => $params['billing_city'],
"country" => $params['billing_country'],
"line1" => $params['billing_address_1'],
"line2" => $params['billing_address_2'],
"postal_code" => $params['billing_postcode'],
"state" => $params['billing_state']
]
],
'amount' => $params['total_price']*100,
'currency' => 'usd',
'payment_method_types' => ['card'],
'metadata' => ['order_id' => $params['order_id']],
'customer' => $customer,
'description' => 'Company - orderid #'.$params['order_id']
]);
$res['clientSecret'] = $paymentIntent->client_secret;
$res['payment_method'] = "stripe";
}
I’m new to working with stripe and not sure how I need to handle the failed payments.
Some payments are failed and some stays in pending state when either the card is declined or due to network issues.
What I wanna do is
1: Add all these orders in a queue with payment status as failed or pending that are older than 5 mins(indicating stripe didn’t called my webhook where I added the logic to mark the order as completed)
2: From the queue, create new payment intent for these orders, or maybe perform another transaction or something so that customer doesn’t has to do anything on their own and if its successfull then fine, otherwise send an email to the customer that it was failed and try another card.
I’m not sure if its possible to perform the transaction again or creating a new payment intent is the right way.
Need suggestions on how to handle these cases efficiently.
Thank you.
2
Answers
You can visualise the Payment Intent object as the order, and the Charge object as a payment attempt.
When you create your Payment Intent, you’re only really setting up the order.
When you confirm the Intent, a Charge object is created – which can either succeed (status=succeeded) or fail (status=failed on the charge and back to requires_payment_method for the Intent).
(Technically there are other statuses like requires_action/pending, but they don’t really make much difference)
Anyway if your attempt to confirm a Payment Intent fails, the Intent reverts back to its initial state. To retry it, all you need to do is to attempt another confirmation (this is assuming you’re using the official flow with a frontend confirmation function, which you should really do).
Payment Intents can have multiple failed Charges like this, but only one Succeeded one – this would close the order.
That said, if you dont want to implement that and instead build new Payment Intents for your retries, that’s completely valid as well.
It is not a good idea to retry
pending
payments. Thepending
status means that the payment is still being processed. It is still highly likely that apending
payment will succeed. So, if you "retry" pending payments, you will end up double charging a lot of customers.For declines in general, I would highly recommend reading Stripe’s docs on handling declines, especially the section on handling them programmatically. When you get a failed payment, you can check the specific decline reason to determine if it is retryable or not.
Typically when you retry like this, you will want to re-use the payment intent as it is intended to track multiple payment attempts for a single thing that the customer is paying for. Re-using the payment intent will also help prevent double-charging users as retrying a successful payment intent will only result in an error.