I'm currently trying to use Laravel Cashier to handle Billing inside a React application. When using a test card that requires 3D secure (pulled directly from Stripes Documentation) (4000000000003220), I get an IncompletePayment exception
throw.
This is apparently normal as described in the documentation:https://laravel.com/docs/6.x/billing#payments-requiring-additional-confirmation
try {
$subscription = $user->newSubscription('default', $planId)
->create($paymentMethod);
} catch (IncompletePayment $exception) {
return redirect()->route(
'cashier.payment',
[$exception->payment->id, 'redirect' => route('home')]
);
}
Now, Laravel recommends that I forward to their 'confirm' page in that scenario. However, this is where my confusion lies. Firstly, I've already asked the customer for their credit card via Stripe Elements inside my React application, so forwarding to a server-side page generated from Laravel is probably going to be a hard NO. I'd like to handle this all gracefully inside my React Application.
I've also already confirmed that the card is valid against 3D secure via a popup like the above, prior to sending anything to the server (which Stripe Elements javascript has already handled for me) so the documentation stating:
On the payment confirmation page, the customer will be prompted to enter their credit card info again and perform any additional actions required by Stripe, such as "3D Secure" confirmation.
Seems like this would be a repetition in any case. Can anyone guide me what I need to do in this scenario? Loosely inside my React App I have the done the following:
Generated a server side intent, and fired it back to react: During the billing process:
stripe.confirmCardSetup(
billingStatus.paymentIntent.client_secret,
{
payment_method: {
card: card,
billing_details: {
name: 'Jenny Rosen'
}
}
}
)
.then((res)=>{
console.log(res);
processPayment( res );
});
The process Payment method hits the server:
var data = new FormData();
data.append( "coreId", plan.id );
data.append( "productId", plan.product_id );
data.append( "planId", plan.stripe_plan_id );
data.append( "paymentMethod", res.setupIntent.payment_method );
billingApi.pay( data, function(res){
BIG FAT 500 SERVER ERROR HERE. (IncompletePayment Exception)
});
I came across an example issue on Github: https://github.com/laravel/cashier/issues/743 Which mirrors very closely my problem.
However, I'm running the latest version of Laravel and Cashier, and checked the line of code quoted in the closed solution is present (which it is) so there may be something else going on.
I'm a bit lost as to what the flow of control should look like to get this working for these types of cards. For standard cards that don't require 3DS, everything works fine. Should I be catching the Exception and handling things differently in React? e.g. Asking for the user to confirm their card details twice?
I should also mention that I have webhooks enabled, and these are resolving successfully locally - I checked in the dashboard.
off_session => true
to buildPayload fixes the issue. – Verdha