How to fix the 3D secure confirm Payment on client side or on server side in Stripe Payment Intent?
Asked Answered
H

2

8

I'm integrating Stripe Payment Intent API and it's working well where 3D secure is not required, 3D secure authorization is popping up but I think I'm missing return_url to confirm the payment.

Where do I need to mention return_url for 3D Secure in PaymentIntent?

I've tried multiple times but got stuck on 3D Secure Authorize. It returns an error in the object.

I've mentioned the code of view and controller below.

Thanks in Advance

Client Side Code:


    form.addEventListener('submit', function(event) {
        event.preventDefault();
    
        $('#card-button').html('<i class="fa fa-circle-o-notch fa-spin" style="font-size:24px"></i>');
        var fname = $('#firstname2').val();
        var lname = $('#lastname2').val();
                    
        var cardholderName = fname + " " + lname;
        var cardButton = document.getElementById('card-button');
        var form_data = $("#payment-form").serialize();
                    
        cardButton.addEventListener('click', function(ev) {
          stripe.createPaymentMethod('card', cardElement, {
            billing_details: {name: cardholderName}
          }).then(function(result) {
            if (result.error) {
             // Show error in payment form
          } else {
             console.log(result);
             // Otherwise send paymentMethod.id to your server (see Step 2)
             fetch('<?php echo base_url(); ?>payment/stripe_test/process_payment', 
             {
               method: 'POST',
               headers: { 'Content-Type': 'application/json' },
               body: JSON.stringify({ payment_method_id: result.paymentMethod.id, customer_detail: form_data})
              }).then(function(result) {
                // Handle server response (see Step 3)
                result.json().then(function(result) {
                console.log("Response" + result);
                handleServerResponse(result);
              });
           });
          }
        });
       });
    }


    function handleServerResponse(response) {
              if (response.error) {
                // Show error from server on payment form
              } else if (response.requires_action) {
                  
                    var action = response.next_action;
                    if (action && action.type === 'redirect_to_url') {
                      window.location = action.redirect_to_url.url;
                    }
                    
                // Use Stripe.js to handle required card action
                stripe.handleCardAction(
                  response.payment_intent_client_secret
                ).then(function(result) {
                  if (result.error) {
                    // Show error in payment form
                  } else {
                    // The card action has been handled
                    // The PaymentIntent can be confirmed again on the server
                    fetch('<?php echo base_url(); ?>payment/stripe_test/process_payment', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({ payment_intent_id: result.paymentIntent.id })
                    }).then(function(confirmResult) {
                      return confirmResult.json();
                    }).then(handleServerResponse);
                  }
                });
              } else {
                // Show success message
                console.log("3D" + response);
              }
            }

CodeIgniter Controller:


    //PaymentIntent Function
        function process_payment() {
            require_once (APPPATH."third_party/stripe/init.php");
                
            $key = "STRIPE_KEY_HERE";
            
            header('Content-Type: application/json');
    
            # retrieve json from POST body
            $json_str = file_get_contents('php://input');
            $json_obj = json_decode($json_str);
            
            $intent = null;
            try {
                if (isset($json_obj->payment_method_id)) {
                  # Create the PaymentIntent
                    //STRIPE PAYMENT INTENT
                    \Stripe\Stripe::setApiKey($key);
                    
                    // Create a Customer:
                    $customer = \Stripe\Customer::create([
                        'email' => '[email protected]',
                    ]);
                    
                    // Attach payment method to the customer:
                    
                    $customer_detail = $json_obj->customer_detail;
                    
                  $intent = \Stripe\PaymentIntent::create([
                    'payment_method' => $json_obj->payment_method_id,
                    'amount' => 1099,
                    'currency' => 'GBP',
                    'confirmation_method' => 'manual',
                    "customer" => $customer->id,
                    'confirm' => true,
                  ]);
                }
                if (isset($json_obj->payment_intent_id)) {
                  $intent = \Stripe\PaymentIntent::retrieve(
                    $json_obj->payment_intent_id
                  );
                  $intent->confirm();
                }
                
                $this->generatePaymentResponse($intent);
                
            } catch (\Stripe\Error\Base $e) {
                # Display error on client
                echo json_encode([
                  'error' => $e->getMessage()
                ]);
            }
        }

generatePaymentResponse Function:


    function generatePaymentResponse($intent) {
            if ($intent->status == 'requires_source_action' &&
                $intent->next_action->type == 'use_stripe_sdk') {
              # Tell the client to handle the action
              echo json_encode([
                'requires_action' => true,
                'payment_intent_client_secret' => $intent->client_secret
              ]);
            } else if ($intent->status == 'succeeded') {
              # The payment didn’t need any additional actions and completed!
              # Handle post-payment fulfillment
              echo json_encode([
                "success" => true
              ]);
            } else {
              # Invalid status
              http_response_code(500);
              echo json_encode(['error' => 'Invalid PaymentIntent status']);
            }
        }

Houston answered 25/4, 2019 at 23:13 Comment(3)
Hi there, you don't need to specify return_url as PaymentIntent will use Popup as 3DS confirmation instead of redirecting. So all you need to do is in your frontend, call stripe.handelCardAction with the client secret. This function will have callback, in the callback, you would ajax to your backend again to confirm the paymentIntent. For details, check this link stripe.com/docs/payments/payment-intents/…Hooks
Thanks @Hooks yeah 3D Secure popup is working but when I click Authorise Payment it returns object as an error and payment incomplete occur on Stripe Dashboard.Houston
I’ve follow stripe document but I’m stuck on it would you please see if I’m missing any step?Houston
A
4

As mentioned in comments, you don't need to specify return_url, because in your case Stripe will use Popup for 3DS confirmation, not redirecting.

You missed two things in your code:
1. In function generatePaymentResponse add condition for $intent->status === 'requires_action'.
2. On Payment Intent confirmation ($intent->confirm();) you missed to set api key (\Stripe\Stripe::setApiKey($key);)

I have tested your code and it works with mentioned modifications.

Artina answered 23/11, 2019 at 17:28 Comment(0)
H
0

Stripe updated the API and few statuses were renamed so the major reason was that I was using requires_source_action as status so replaced it with requires_action.

Stripe Update - 2019-02-11


  • Some PaymentIntent statuses have been renamed

    • requires_source is now requires_payment_method
    • requires_source_action is now requires_action
    • All other statuses are unchanged
  • save_source_to_customer has been renamed to save_payment_method.

  • allowed_source_types has been renamed to payment_method_types.

  • The next_source_action property on PaymentIntent has been renamed to next_action, and the authorize_with_url within has been renamed to redirect_to_url.


You can find Stripe Api upgrades here: https://stripe.com/docs/upgrades#api-versions.

Houston answered 12/2, 2023 at 10:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.