skip to Main Content

When using Stripe with ReactJS, I am confused about where to submit the payment tokens after the user has filled out their credit card info. I have this payment container that gets a peyment intent from my server …

  useEffect(() => {
    OrderService.createPaymentIntent(cart)
      .then((paymentIntent) => {
        setOrderTotal(paymentIntent.orderTotal);
        setOptions({ ...options, clientSecret: paymentIntent.clientSecret });
        setOrderTotal(paymentIntent.orderTotal);
      })
      .catch((error) => {
        console.error("Error fetching profile:", error);
      });
  }, []);
    ...          {options?.clientSecret && (
            <Elements options={options} stripe={stripePromise}>
              <CheckoutForm />
            </Elements>

      )}

and below I have my CheckoutForm.tsx file. However, I’m confused about where to submit the data obtained from the "createToken" call. Does this need to be submitted to my server to in turn submit to stripe or should this be submitted directly to stripe?

  const stripe = useStripe();
  const elements = useElements();
    ...

  const handleSubmit = (ev) => {
    ev.preventDefault();

    const cardElement = elements?.getElement("card");

    stripe
      ?.createToken(cardElement) 
      .then((payload) => console.log("[token]", payload)); 
  };
  return (
    <form onSubmit={handleSubmit}>
      <PaymentElement />
      <button disabled={!stripe}>Submit</button>
    </form>
  );
};

If this is submitted directly to stripe, how do I record on my server what happened with this particular order?

2

Answers


  1. From the code snipped you shared, it looks like you’re using Card Elements and Token which are their legacy approach and you should instead use Payment Elements.

    Just a bit more context on what Payment Elements does. The Payment Element offers an embedded UI component for you to accept many Payment Methods securely with one integration. Depending on where your customer is, it dynamically sorts the Payment Method to optimize conversion, adjusts input fields automatically for different Payment Methods, validates inputs to reduce friction for card payments. In the future, if you decide to add other payment methods, you can just enable them in your Dashboard to start supporting them on your Checkout page. Here is their integration guide that you can use as a guidance.

    After the customer provides payment method details, you can confirm the Payment on the client-side. Is there are any immediate errors, Stripe.js returns that error. If there is not, you can listen to wehbook events to handle post payment actions.

    Login or Signup to reply.
  2. Based on the code provided, which seems taken from the Stripe documentations, you have reached the final step of the integration for "Creating an account" or "Create a person". That means that after receiving the token, you are now suppose to send it to your backend as a final step in order to create an account and/or a person on your backend using Stripe. Check this link for more details: https://stripe.com/docs/connect/account-tokens

    BUT this is useful only for cases where you need tokens to ensure that personally identifiable information (PII) doesn’t reach your servers.

    What you’d rather do to confirm the PaymentIntent is to use stripe.confirmCardPayment. Check the Stripe.js docs on: https://stripe.com/docs/js/payment_intents/confirm_card_payment.

    An example of implementing it might be the following code:

    async function submitOrder(data) {
            setLoading(true);
            const { nameOnCard, saveAddress, ...shippingAddress } = data;
            if (!stripe || !elements || !clientSecret) {
                // Stripe.js hasn't yet loaded.
                // Make sure to disable form submission until Stripe.js has loaded.
                return;
            } // Stripe is not ready
            try {
                const cardElement = elements.getElement(CardNumberElement); // CardNumberElement is imported from @stripe/react-stripe-js as well
                const paymentResult = await stripe.confirmCardPayment(clientSecret, {
                    payment_method: {
                        card: cardElement,
                        billing_details: {
                            name: nameOnCard, // sending additional properties
                        },
                    },
                });
                console.log(paymentResult); // you can visualize the result in the console
    
                if (paymentResult.paymentIntent?.status === "succeeded") {
                    // create the order in the back-end                
                    setPaymentSucceeded(true); // use as many flags as you want
                    setPaymentMessage("Thank you - we have received your payment");
                    setLoading(false);
                } else {
                    setPaymentMessage(paymentResult.error?.message || "Payment failed");
                    setPaymentSucceeded(false);
                    setLoading(false);
                }
            } catch (error) {
                console.log(error);
                setLoading(false);
            }
        }
    

    After that, as said in the other answer by @pgs: "If there are any errors, Stripe.js returns that error. If there is not, you can listen to webhook events to handle post payment actions."

    I hope that helps at least a bit.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search