#jojilede-setupintent-confirmation

1 messages ยท Page 1 of 1 (latest)

jade harborBOT
lean anvil
#

jojilede-setupintent-confirmation

#

Hey @compact pilot you say you create a SetupIntent, but the error says "No such payment_intent" which tells me you must be calling the wrong method likely client-side

#

can you share your exact code?

compact pilot
#

ok, sure:

#

api/payment/create-setup-intent.ts:

import Stripe from 'stripe';

const stripe = new Stripe(process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY_TEST, {
  apiVersion: '2022-11-15',
});

export default async function createSetupIntent(req, res) {
    try {
        const setupIntent = await stripe.setupIntents.create({
            customer: req.body.customerId,
            payment_method_types: req.body.payment_method_types,
            usage: 'off_session'
        });
        res.json({client_secret: setupIntent.client_secret});
    } catch (err) {
        res.status(500).json({statusCode: 500, message: err.message});
    }
}
lean anvil
#

okay so that creates a SetupIntent

compact pilot
#

component using it:

useEffect( () => {
    (async () => {
      const response = await axios.post('/api/payment/create-setup-intent', {
        body: {
          customerId: loggedUserData.GetLoggedUser?.UserProfile?.StripeCustomerId,
        },
        payment_method_types: ['bancontact', 'card', 'ideal']
      });
      setClientSecret(response.data.client_secret)
    })();
  }, [])

  return (
    <Layout>
      {
        clientSecret && (
          <Elements 
            stripe={props.stripePromise} 
            options={{
              clientSecret, 
              appearance: 
              { 
                theme: 'flat',
                variables: {
                  colorPrimary: '#0570de',
                  colorBackground: '#ffffff',
                  colorText: '#30313d',
                  colorDanger: '#df1b41',
                  fontFamily: 'Ideal Sans, system-ui, sans-serif',
                  spacingUnit: '2px',
                  borderRadius: '4px',
                }
              }
            }} >
            <CheckoutForm />
          </Elements>
        )
      }
    </Layout>

#

CheckoutForm:

import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js';

const CheckoutForm = () => {
  const stripe = useStripe();
  const elements = useElements();

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    // We don't want to let default form submission happen here,
    // which would refresh the page.
    event.preventDefault();

    if (!stripe || !elements) {
      // Stripe.js has not yet loaded.
      // Make sure to disable form submission until Stripe.js has loaded.
      return;
    }

    const result = await stripe.confirmPayment({
      //`Elements` instance that was used to create the Payment Element
      elements,
      confirmParams: {
        return_url: "/customer-payments",
      },
    });

    if (result.error) {
      // Show error to your customer (for example, payment details incomplete)
      console.log(result.error.message);
    } else {
      // Your customer will be redirected to your `return_url`. For some payment
      // methods like iDEAL, your customer will be redirected to an intermediate
      // site first to authorize the payment, then redirected to the `return_url`.
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <PaymentElement />
      <button disabled={!stripe}>Submit</button>
    </form>
  )
};

export default CheckoutForm;

lean anvil
compact pilot
#

haha! checking now

#

do I just replace the confirmPayment with confirmSetup? and the rest is the same?

lean anvil
#

mostly yes

#

I wish it "just worked" with one method so that you never had to think about it. One day!

compact pilot
#

nice! it gave me new error now can you help me again?

lean anvil
#

If you share the exact error and relevant details yes ๐Ÿ™‚

compact pilot
#

thanks,:

{
    "code": "url_invalid",
    "doc_url": "https://stripe.com/docs/error-codes/url-invalid",
    "message": "Not a valid URL",
    "param": "return_url",
    "request_log_url": "https://dashboard.stripe.com/test/logs/req_QmD5ysJSeOJVET?t=1673635271",
    "setup_intent": {
        "id": "seti_1MPsBQDTISXyBnp6m1p7PviB",
        "object": "setup_intent",
        "cancellation_reason": null,
        "client_secret": "seti_1MPsBQDTISXyBnp6m1p7PviB_secret_NACawQYkDVh5Gu4RVFBQKRS4yjGqioQ",
        "created": 1673635256,
        "description": null,
        "last_setup_error": null,
        "livemode": false,
        "next_action": null,
        "payment_method": null,
        "payment_method_types": [
            "bancontact",
            "card",
            "ideal"
        ],
        "status": "requires_payment_method",
        "usage": "off_session"
    },
    "type": "invalid_request_error"
}
#

got that preview return.

#

btw the return_url: "/customer-payments"

#

and it's the same as to where this url is

lean anvil
#

that feels fairly self explanatory right?

#

basically you have to be explicit and pass a full URL, you can't just pass a relative URL

compact pilot
#

omg

#

thank you so much.

#

it's bc it's a localhost so I thought that will work.

lean anvil
#

yeah common misunderstanding ๐Ÿ™‚

compact pilot
#

so now I had to create an env variable for localhost like usual or you have other recommendation?

lean anvil
#

I don't really understand what that could mean

#

you could use window.location.hostname for example and append the route?

compact pilot
#

I was just explaining and typing that as option and you beat me into it haha

lean anvil
#

๐Ÿ™‚

compact pilot
#

so it will really do a full page reload.

lean anvil
#

it's a full page redirect yes

compact pilot
#

I see, it's ok tho ๐Ÿ˜„ Thanks for helping! you're one of my favorite.

lean anvil
#

LOL thank you. We'll see if that lasts as you talk to more people on my team :p

compact pilot
#

haha! I don't want to eat more of your time. Thank you so much!

lean anvil
#

Have a great rest of the day!