javascriptstripe-paymentssca

Stripe Subscription incomplete after 3DS check


I'm not sure I understand this "new" Stripe SCA 3DS flow. When I successfully complete the 3DS authentication, create a customer, then the subscription, the subscription is marked as "incomplete".

This is my current Javascript implementation:

form.addEventListener('submit', function(event) {

    event.preventDefault();
    disableFormSubmit(true);

    stripe.confirmCardPayment($('input#client_secret').val(), {

        payment_method: {
            card: cardElement,
            billing_details: {
                name: $('input#first_name').val()+' '+$('input#last_name').val(),
                email: $('input#email').val(),
            }
        }

    }).then(function(result){

        console.log(result);

        if (result.error) {
            disableFormSubmit(false);
            showPaymentError(result.error.message);
        } else {
            if (result.paymentIntent.status === 'succeeded') {
                disableFormSubmit(true);
                $('input#payment_method').val(result.paymentIntent.payment_method);
                form.submit();
            }
        }

    });
});

confirmCardPayment already takes care of the validation, showing me this overlay, where I click "Complete Authentication".

enter image description here

Following this, the customer (and payment method) is successfully created and a subscription is attached to the customer. But the subscription status now says "incomplete" with "requires_action". Now this is what I don't understand. Isn't the previous overlay responsible for this? According to the docs (https://stripe.com/docs/billing/subscriptions/set-up-subscription#manage-sub-status) I should call confirmCardPayment again, which I do not understand as I just did that, see JS code.

enter image description here

Why is my subscription still incomplete with a "requires_action" status even though I literally just completed this step?


Solution

  • The part of the guide you're looking at is about handling additional authentication actions and recovering from failed payments. You should only be providing the client_secret at this point:

    stripe.confirmCardPayment(client_secret)
    

    In your code snippet, you're providing the cardElement again, when it was already provided earlier:

    stripe.createPaymentMethod({
      type: 'card',
      card: cardElement, // <-------
      billing_details: {
        email: 'jenny.rosen@example.com',
      },
    })
    

    I suspect something unexpected is happening because of this, so adjust your code to follow the flow of the guide and it should work.