How do I create a token for the new stripe payment element as it used to be done in the old card element?

758 Views Asked by At

I am trying to use the new payment element in stripe for payment handling in my react application but the backend that was implemented requires me to send the tokenized payment details collected through stripe and send through which the backend will create a charge. The examples I have seen don't do that and all process the payment directly with stripe. All the examples I have seen using the token doesn't seem to work for payment element and only work for the old card element.

Here is the form:

<form id="payment-form" onSubmit={handleSubmit}>
      <LinkAuthenticationElement
        id="link-authentication-element"
        onChange={(e) => setEmail(e.target.value)}
      />
      <PaymentElement id="payment-element" options={paymentElementOptions} />
      
      <button className="mt-5 rounded-lg text-center flex items-center justify-center w-full px-8 py-4 bg-main text-white border-0 text-sm leading-4 font-medium sm:font-semibold sm:text-base sm:leading-[19px]" disabled={isLoading || !stripe || !elements} id="submit">
        <span id="button-text">
          {isLoading ? <div className="spinner" id="spinner"></div> : "Pay now"}
        </span>
      </button>
      {/* Show any error or success messages */}
      {message && <div id="payment-message" className="text-center mt-2">{message}</div>}
    </form>

Here is an example of the old method using card element:

stripe.createToken(card).then(function(result) {
      if (result.error) {
        // Inform the user if there was an error.
        var errorElement = document.getElementById('card-errors');
        errorElement.textContent = result.error.message;
      } else {
        // Send the token to your server.
        stripeTokenHandler(result.token);
      }
    });

I have tried the following but none seems to work:

const cardElement = elements.getElement(cardElement);
stripe.createToken(cardElement).then(function(result) {
      if (result.error) {
        // Inform the user if there was an error.
        // var errorElement = document.getElementById('card-errors');
        // errorElement.textContent = result.error.message;
        console.log(result.error.message)
      } else {
        // Send the token to your server.
        console.log(result);
      }
    }).catch((error) => {
      console.log(error);
    });
3

There are 3 best solutions below

2
os4m37 On

The new Stripe PaymentElements requires the use of the new PaymentIntent and PaymentMethods APIs. I invite you to refer to this guide in order to migrate from Tokens to PaymentMethods. You need to change:

stripe.createToken(
  cardElement
).then(function(token) {
 // Send token to server
});

Into something like this:

stripe.confirmCardPayment(
 INTENT_SECRET_FROM_STEP_1,
 {
  payment_method: {card: cardElement}
 }
).then(function(result) {
  if (result.error) {
   // Display error.message in your UI.
  } else {
   // The payment has succeeded
   // Display a success message
  }
 });
2
Lucky2501 On

This is the closest thing to it with the payment element:
https://stripe.com/docs/payments/build-a-two-step-confirmation

In it you create the Payment Method using the createPaymentMethod funcion, which corresponds to your current createToken one.

  // Create the PaymentMethod using the details collected by the Payment Element
const {error, paymentMethod} = await stripe.createPaymentMethod({
   elements,
   params: {
   billing_details: {
     name: 'Jenny Rosen',
     }
   }
});

You can then use this Payment Method on the backend with your Payment Intent.

Still, it might not completely suit, because this flow still uses a confirmPayment() function on the frontend, which differs from what I'm guessing you use. I'm picturing your integration working with more of a backend confirmation, like in this legacy flow:
https://stripe.com/docs/payments/accept-a-payment-synchronously

0
Nam Quan Tran On

The same situation as me. I looked at the Stripe document and see that the Stripe api createToken doesn't accept the new PaymentElement.

Then, I think currently, there is no way to create the token from the Payment Element. So, either you need to update Backend to consume paymentIntent (produced by PaymentElement) or update the Frontend to use old Stripe Card elements which are tokenizable..

Ref: https://stripe.com/docs/js/tokens/create_token?type=cardElement