2
votes

I'm struggling to get Stripe to work on my server.

So, on the client side, I have this code (after much struggle to get element working) :

this.props.stripe.createPaymentMethod({ type: 'card', card: cardElement, billing_details: { name: name } }).then((paymentMethod) => {
        // server request with customer_id and paymentMethod.id);
      });

This works fine. Now, on the server (NodeJS), I want to add a new on-going subscription with a fixed fee for my customer.

Here's what I have :

const paymentIntent = await stripe.paymentIntents.create({
          amount: 1000,
          currency: 'usd',
          payment_method_types: ['card'],
          customer: req.body.customer_id,
          metadata: { integration_check: 'accept_a_payment' },
        });

const paymentIntentConfirmation = await stripe.paymentIntents.confirm(paymentIntent.id, { payment_method: req.body.paymentMethod_id });


const newSubscription = await stripe.subscriptions.create({
          customer: req.body.customer_id,
          items: [{ plan: premium_plan.id, quantity: 1 }],
          default_payment_method: req.body.paymentMethod_id,
        });
const attachPaymentToCustomer = await stripe.paymentMethods.attach(req.body.paymentMethod_id, { customer: req.body.customer_id });


const updateCustomerDefaultPaymentMethod = await stripe.customers.update(req.body.customer_id, {
      invoice_settings: {
        default_payment_method: req.body.paymentMethod_id,
      },
    });

So, if I don't attach the payment to customer, I get the following error message :

'The customer does not have a payment method with the ID pm_1Gx9m1HVGJbiGjghYhrkt6j. The payment method must be attached to the customer.'

If I do, I get the following error message :

'This PaymentMethod was previously used without being attached to a Customer or was detached from a Customer, and may not be used again.'

So, how do I add the damn payment method, so when I retrieve my customer, it shows this customer has been updated with a new subscription to the service he just subscribed to, together with his payment method (a CC in this case).

Any help here for a frustrated user is very appreciated !

On a more general note, implementing Stripe has been a very painful experience so far. Nothing seems to work. I use Typescript and there are so many bugs. The documentation is not very helpful and not well explained. "Create a source", "create a token", "create a payment intent", "create a setup intent", how am i supposed to understand the difference between all these things ? I want to add a god damn online subscription, which should be quite a standard procedure for an Internet service. Why are there so many different guidelines, with tokens, with sources, etc....

1
I humbly agree.Ricky-U
It's comforting to see someone felt the exact same way about this. Well said.metamonkey

1 Answers

5
votes

There's a few changes you can make here to get it working, in order to start a Subscription [1] you don't need to create and confirm a PaymentIntent. That is created automatically inside the Invoice(s) as they're created for payment. So the steps roughly are (you've done a lot of this already but just to have an end to end example):

  1. Create a customer
  2. Collect the payment information securely using Stripe.js
  3. Attach the PaymentMethod to the Customer
  4. (Optionally) save that as the invoice settings default payment method (because you can pass the PaymentMethod to the Subscription creation as a default payment method, but it's good practice so that you can start Subscriptions for that Customer with the same payment method)
  5. Create a Subscription
  6. Provision your service
  7. Take into account SCA/3DS and handle authentication [2]

That's outlined in detail on [1]. Here's some sample code to get the Subscription started, you can replace the calls that create products and prices with your own IDs of course:

const customer = await stripe.customers.create({
  name: "Foo Bartley"
});

const paymentMethod = await stripe.paymentMethods.create(
  {
    type: 'card',
    card: {
      number: '4242424242424242',
      exp_month: 6,
      exp_year: 2021,
      cvc: '314',
    },
  }
);

const product = await stripe.products.create(
  {name: 'Gold Special'}
);

const price = await stripe.prices.create(
  {
    unit_amount: 1111,
    currency: 'eur',
    recurring: {interval: 'month'},
    product: product.id,
  }
);

// Everything above here is just setting up this demo

const attachPaymentToCustomer = await stripe.paymentMethods.attach(
  paymentMethod.id,  // <-- your payment method ID collected via Stripe.js
  { customer: customer.id } // <-- your customer id from the request body  
  
); 

const updateCustomerDefaultPaymentMethod = await stripe.customers.update(
  customer.id, { // <-- your customer id from the request body
  
    invoice_settings: {
      default_payment_method: paymentMethod.id, // <-- your payment method ID collected via Stripe.js
    },
});

const newSubscription = await stripe.subscriptions.create({
  customer: customer.id, // <-- your customer id from the request body
  items: [{ plan: price.id, quantity: 1 }], // <-- plans and prices are compatible Prices is a newer API
  default_payment_method: paymentMethod.id, // <-- your payment method ID collected via Stripe.js
});

Hope this helps!

[1] https://stripe.com/docs/billing/subscriptions/fixed-price#create-subscription

[2] https://stripe.com/docs/billing/subscriptions/fixed-price#manage-payment-authentication