Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stripe Intent API Hold Card and then Charge Not Working

I'm trying to implement a pretty straightforward flow for my product:

  1. Customer adds card to his account

  2. Customer makes a request -> Create a hold on his card for the request price

  3. On request delivered -> Execute the initial hold made on the card

Upon reading through loads of docs on Stripe's new Intent API, this seemed pretty simple.

A. Create a Stripe customer

stripe.customers.create({ email: user.email, description:Customer for ${user.email}});

B. Attach a card (payment method) to the customer, create a setup intent with this card to authorize future charges

stripe.setupIntents.create({ 'customer': customer_id, 'payment_method': paymentMethodId });

C. On a request made by the customer, create paymentIntent with capture_method set to manual

const paymentIntent = await stripe.paymentIntents.create({
    'amount': price * 100, //convert shekels to agorot
    'currency': 'ILS',
    'customer': customer_id,
    'payment_method': payment_method,
    'payment_method_types': ['card'],
    'capture_method': 'manual'
});

D. On request delivered, simply capture the original paymentIntent created in step C.

const captureHoldIntent = await stripe.paymentIntents.capture(paymentIntentId);

The issue I'm getting actually is occurring between steps C and D:

Failed to save transaction for user_id KAJSD92 error Error: This PaymentIntent could not be captured because it has a status of requires_confirmation. Only a PaymentIntent with one of the following statuses may be captured: requires_capture.

While I understand this error message, my confusion is as to why the paymentIntent created in step C doesn't change to the requires_capture status and is instead always require_confirmation, even though it has already been confirmed?

like image 315
royherma Avatar asked Oct 16 '19 07:10

royherma


Video Answer


1 Answers

The missing piece was calling paymentIntents.confirm to "confirm" that the service actually wants to place a hold on the card. After that, the intents status was changed to requires_capture which allowed me to call the capture method.

  1. Create
const paymentIntent = await stripe.paymentIntents.create({
            'amount': price * 100, //convert shekels to agorot
            'currency': 'ILS',
            'customer': customer_id,
            'payment_method': payment_method,
            'payment_method_types': ['card'],
            'capture_method': 'manual'
        });
  1. Confirm

const confirmPaymentIntent = await stripe.paymentIntents.confirm(intentId);

  1. Capture

const captureHoldIntent = await stripe.paymentIntents.capture(intentId);

like image 144
royherma Avatar answered Oct 10 '22 00:10

royherma