0
votes

I'm building a donation form for a non-profit and I'm struggling with updating the updated payment amount sent to my Node.js Stripe backend.

Frontend is React and I'm using the useEffect() hook to create my paymentIntent. It appears that with the new Stripe API the amount is required to return the clientSecret. Otherwise, I would want to create the paymentIntent after the user chooses the donation amount (as I've done with a similar implementation).

I'm using the method "stripe.paymentIntents.update()" to update the amount. This shows updated in the console.log, but it's not updating the paymentIntent sent to Stripe.

How do I update the paymentIntent to send to confirmCardPayment()?

server.js

  app.post("/create-payment-intent", async (req, res) => {
  let amount = req.body.amount;
  const name = req.body.name;
  
  const options = {
    description: 'Teton Valley Aquatics Donation',
    amount,
    currency: "USD",
    name: name,
  };

  console.log(req.body.amount) //returns my default amount {1000}

  try {
    const paymentIntent = await stripe.paymentIntents.create(options);
    res.json(paymentIntent);
  }
   catch (err) {
    res.json(err);
  }

app.post("/create-payment-intent/update-amount", async (req, res) => {
  const amount = req.body;
  console.log(req.body) //returns {amount: 25}
  try {
    const paymentIntent = await stripe.paymentIntents.update(amount, {
      amount,
    });
    console.log(`Updated amount: ${amount}`);
    res.json(paymentIntent);
  }
  catch (err) {
    res.json(err)
  }
})
});

CheckoutForm.jsx

useEffect(() => {
api
.createPaymentIntent({
  amount
})
.then((clientSecret) => {
  setClientSecret(clientSecret);
})
.catch((err) => {
  setError(err.message);
});

console.log(`Amount: ${amount}`)
}, []);


  const handleSubmit = async (ev) => {
    ev.preventDefault();
    setProcessing(true);
    
    api
      .updatePaymentIntent({
        amount,
      })
      .catch((err) => {
        setError(err.message);
      });

    const payload = await stripe.confirmCardPayment(clientSecret, {
      payment_method: {
        card: elements.getElement(CardElement),
        billing_details: {
          name: ev.target.name.value,
          email: ev.target.email.value
        },
      },
    });

    if (payload.error) {
      setError(`Payment failed: ${payload.error.message}`);
      setProcessing(false);
      console.log("[error]", payload.error);
    } else {
      setError(null);
      setSucceeded(true);
      setProcessing(false);
      setMetadata(payload.paymentIntent);
      console.log("[PaymentIntent]", payload.paymentIntent);
    }
  };

api functions

const createPaymentIntent = options => {
  return window
    .fetch(`http://localhost:4242/create-payment-intent`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(options)
    })
    .then(res => {
      if (res.status === 200) {
        return res.json();
      } else {
        return null;
      }
    })
    .then(data => {
      if (!data || data.error) {
        console.log("API error:", { data });
        throw new Error("PaymentIntent API Error");
      } else {
        return data.client_secret;
      }
    });
};

const updatePaymentIntent = options => {
  return window
    .fetch(`http://localhost:4242/create-payment-intent/update-amount`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(options)
    })
    .then(res => {
      if (res.status === 200) {
        return res.json();
      } else {
        return null;
      }
    })
    .then(data => {
      if (!data || data.error) {
        console.log("API error:", { data });
        throw new Error("PaymentIntent API Error");
      } else {
        return data.client_secret;
      }
    });
}
1

1 Answers

2
votes

The first parameter to update should be a payment intent id. It seems you have a typo/bug putting the amount in twice:

const paymentIntent = await stripe.paymentIntents.update(**amount**, {
  amount,
});

should be:

const paymentIntent = await stripe.paymentIntents.update(**paymentIntentId**, {
  amount,
});

See the snippet here: https://stripe.com/docs/api/payment_intents/update?lang=node