0
votes

How to pay for multiple subscriptions at once for the first time.

A customer can choose multiple subscriptions, some of them are with monthly payment and others with half-yearly payment.

When the customer chooses the subscriptions he adds them to the cart.

I do this on the server side for the creation of a customer (stripe.com/docs/billing/subscriptions/elements#create-customer)

$customer = $stripe->customers->create([
'email' => $this->getUser()->getEmail(),
]);

then I create the subscriptions (https://stripe.com/docs/billing/subscriptions/multiple)

$sub1 = $stripe->subscriptions->create([
  'customer' => 'cus_4fdAW5ftNQow1b',
  'items' => [['price' => 'price_CZB2krKbBDOkTe']],
  'payment_behavior' => 'default_incomplete',
  'expand' => ['latest_invoice.payment_intent'],
]);

$sub2 = $stripe->subscriptions->create([
  'customer' => 'cus_4fdAW5ftNQow1b',
  'items' => [['price' => 'price_CZB1AX3KOacNJb']],
  'payment_behavior' => 'default_incomplete',
  'expand' => ['latest_invoice.payment_intent'],
]);

However, in the doc cite:

"On the backend, create the subscription with status incomplete using payment_behavior=default_incomplete and returns the client_secret from the payment intent to the frontend to complete payment."

The problem I have is that I have one client_secret for each subscription. So, how to pay (for the first time, start of the subscriptions) in one credit card form.

In the front end I have this:

    
let stripePublicKey = "{{ stripePublicKey }}"
            
let stripe = Stripe(stripePublicKey);
let elements = stripe.elements();

//let clientSecret = {{clientSecret}} // the secret client is requested in the function stripe.confirmCardPayment below

//Create an instance of an Element and mount it to the Element container
let card = elements.create('card');
card.mount('#card-element');

            
function displayError(event) {
    //changeLoadingStatePrices(false);
    let displayError = document.getElementById('card-element-errors');
    if (event.error) {
            displayError.textContent = event.error.message;
    } else {
            displayError.textContent = '';
            }
    }

    card.addEventListener('change', function (event) {
        displayError(event);
    });


    const btn = document.querySelector('#submit-payment-btn');
    btn.addEventListener('click', async (e) => {
        e.preventDefault();
        const nameInput = document.getElementById('name');

        // Create payment method and confirm payment intent.
        stripe.confirmCardPayment(clientSecret, {
            payment_method: {
                card: cardElement,
                billing_details: {
                    name: nameInput.value,
                    },
                }
        }).then((result) => {
            
            if(result.error) {
                alert(result.error.message);
            } else {
                // Successful subscription payment

                }
        });
    });

    

Is this possible? If not what approach should I consider?

Thanks!

UPDATE

If I make a loop to pay, is it wrong?

const btn = document.querySelector('#submit-payment-btn');
btn.addEventListener('click', async (e) => {
            e.preventDefault();
            for(const [key, value] of Object.entries(clientSecrets)) {
                // Create payment method and confirm payment intent.
                await stripe.confirmCardPayment(value.secret, {
                    payment_method: {
                        card: card,
                        billing_details: {
                            name: '{{app.user.fullName}}'
                        },
                    }
                }).then((result) => {
                    if (result.error) {
                        alert(result.error.message);
                    } else {
                        // Successful subscription payment
                        console.log('Successful subscription payment');
                    }
                });
                
            }
});

Can it cause problems?

2

2 Answers

0
votes

You can't do this the way you're trying, as you noted these are separate Payment Intents (each with their own client_secret).

When you follow the default_incomplete integration path, when you confirm the payment intent from the first subscription, the payment method will be attached to the customer and ready for future usage. Once that's successful, you and use that attached payment method to create the second subscription, either by providing the default_payment_method explicitly (API ref), or by setting the customer invoice_settings[default_payment_method] first (API ref). You may still encounter an authentication request, at the discretion of your customer's bank, so make sure you check for and handle those cases.

0
votes
$sub1 = $stripe->subscriptions->create([
'customer' => 'cus_4fdAW5ftNQow1b',
'items' => [
      ['price' => 'price_CZB2krKbBDOkTe'],
      ['price' => 'price_CZB1AX3KOacNJb']
],
'payment_behavior' => 'default_incomplete',
'expand' => ['latest_invoice.payment_intent'],
]);