#jev-webhooks-express

1 messages · Page 1 of 1 (latest)

green shuttleBOT
#

Hello! We'll be with you shortly. Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.

tired nova
rose sleet
#

I think that is a complicated approach, i am managing confirmPayment and confirmCardPayment, on confirmCardPayment I could make some fetch to my endpoint to manipulate like this:

  const response = await axios.post('/api/v1/stripe/create-payment-intent', {
        amount: amounts.total,
        currency: 'mxn',
        customerId: customerId,
        paymentMethodId: paymentMethodId, // Usa el método de pago guardado
      })

      const clientSecret = response.data.client_secret

      // Confirma el pago con el método de pago guardado
      const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
        payment_method: paymentMethodId,
        return_url: `http://localhost:5173/success`,
      })

      if (error) {
        setErrorMessage(error.message)
      } else {
        // Maneja el éxito del pago aquí
        // TODO redirigir a success o cerrar todos los modales y mostrar notificacion
        const response = await axios.post(`/api/v1/stripe/confirm-payment`, {
          venueId: params.venueId,
          billId: params.billId,
          amount: amounts.amount,
          tipPercentage: tipPercentage,
          avoFee: amounts.avoFee,
        })

        navigate(`/success?payment_intent=${paymentIntent.id}`)
        showNotification()
      }

i want something similar on my confirmPayment

tired nova
#

I mean it's upto you on how to handle this. If you make these calls from your client-side code then it's easy for an fraudster to modify your code and mess with your application.

rose sleet
#

Well, this payment only applies when I get a response from my backend that the payment is completed, if not then the payment will not be applied

tired nova
#

Generally, I've seen folks use webhook events to trigger database related changes.

Well, this payment only applies when I get a response from my backend that the payment is completed, if not then the payment will not be applied
Right but in the code you shared, I see that you're creating PaymentIntent using your client-side code which exposes your private API key.

#

oh wait

#

nvm I read it wrong

rose sleet
#

Dont worry

#

I just want to make this approach on my confirmPayment

    try {
      const { user } = getUserLS()

      const response = await axios.post(`/api/v1/stripe/create-payment-intent`, {
        amount: amounts.total,
        currency: 'mxn',
        customerId: user.stripeCustomerId,
      })
      const { client_secret: clientSecret, id } = response.data

      const { error } = await stripe.confirmPayment({
        elements,
        clientSecret,
        confirmParams: {
          return_url: `http://localhost:5173/pene`,

        },
      })

      if (error) {
        handleError(error)
      } else {
        console.log('THIS DOES NOT GET EXECUTED')
        const response = await axios.post(`/api/v1/stripe/confirm-payment`, {
          venueId: params.venueId,
          billId: params.billId,
          amount: amounts.amount,
          tipPercentage: tipPercentage,
          avoFee: amounts.avoFee,
        })
        setShowTipModal(false)
        // Maneja el éxito del pago aquí
      }
    } catch (error) {
      setErrorMessage(error.message)
    } finally {
      setLoading(false)
    }
  }
rose sleet
tired nova
#

again, upto you on how you want to handle it.

Based on the code above, on a successful payment you'd be redirected to http://localhost:5173/pene

That's where you should check if the pi_xxx was confirmed successfully and if so, you can make the other request to your server

const response = await axios.post(`/api/v1/stripe/confirm-payment`, { venueId: params.venueId, billId: params.billId, amount: amounts.amount, tipPercentage: tipPercentage, avoFee: amounts.avoFee, }) setShowTipModal(false)

#

I'm guessing the above code doesn't execute because you're getting redirected?

rose sleet
#

But in confirmCardPayment, i did almost the same approach

#

so the http://localhost:5173/pene should be a backend route? verify if the data is correct and then redirect to the /success component correcly?

tired nova
rose sleet
# rose sleet so the http://localhost:5173/pene should be a backend route? verify if the data ...
import useModal from '@/hooks/useModal'
import { useQuery } from '@tanstack/react-query'
import axios from 'axios'
import { Link, useSearchParams } from 'react-router-dom'
import Receipt from './Receipt'
import { Button } from '@/components/Button'

const Success: React.FC = () => {
  const [searchParams, setSearchParams] = useSearchParams()
  const paymentIntentId = searchParams.get('payment_intent')

  const { openModal, closeModal, isModalOpen } = useModal()

  const { data, isLoading, isError, error } = useQuery({
    queryKey: ['paymentIntent', paymentIntentId],
    queryFn: async () => {
      const response = await axios.get(`/api/v1/stripe/payment-intent/${paymentIntentId}`)

      return response.data
    },
  })

  if (isLoading) {
    return <div>Loading...</div>
  }
  if (isError) {
    return <span>Error: {error.message}</span>
  }

  return (
    <div>
      <h1>Payment Successful!</h1>
      <p>Pagaste: {data.amount / 100}</p>

      <Receipt isOpen={isModalOpen.receipt} closeModal={() => closeModal('receipt')} paymentIntentId={paymentIntentId} />
      <Button type="button" text="Obtener recibo" onClick={() => openModal('receipt')} />
      <Link to={-1}>Volver a la página principal</Link>
    </div>
  )
}

export default Success

this is on my success route

tired nova
#

You'd need to test the code 🙂 We can't say what's wrong with it just by looking at it

rose sleet
#

yes, but each time some user gets redirected to this route, the user can reload the page and the payment would get applied again

tired nova
#

Yeah so you'd need to prevent that from happening!
this is also something you'd avoid if you handle database manipulations server-side using webhooks as the webhook event will only be delivered once

rose sleet
#

ok thx hanzo

#

Can i make webhooks for my localhost?

tired nova
#

sure

rose sleet
#

how?

#

with stripe login?

tired nova
rose sleet
#

oks

#

thanks

green shuttleBOT
rose sleet
#

In what part I need to implement the webhook in my code?

When the payment gets applied then what

simple mist
#

HI 👋

I"m taking over and catching up. You've posted a lot of code but, in order to help me, can you describe in simple steps what your integration is doing?

rose sleet
#

NVm, i have a new question, i dont know each time i pay something, the webhook gets 4 events why?

simple mist
#

each time i pay something

  1. What are you using to collect payment?
  2. What are the event types you are receiving?
rose sleet
#

200, im using stripe trigger CLI

simple mist
#

What command are you using?

rose sleet
#

stripe trigger payment_intent.succeeded

simple mist
#

Okay, in order to work, that trigger runs a set of fixtures

#

So for a payment intent to succeed first it must be created, which fires an event. Also, when a payment intent is paid it creates a Charge object which fires events as well

rose sleet
#

ok but it would not create multiple database mutations?

simple mist
#

That is something you get to work out in terms of how you design your integration to respond to webhook events.

rose sleet
#

I didnt understand, Im afraid that if I get 3 responses, then the database will be manipulated 3 times..

simple mist
#

Only if your code manipulates the database. You have a choice there.

But lets step back. The webhook events fire to inform you of changes. What is the problem with the database being updated 3 times?

rose sleet
#

well, if in the webhook i will add a payment, then it will add 3 payments

simple mist
#

But that doesn't make sense. The Payment Intent returned in payment_intent.created and payment_intent.payment_succeeded is the same Payment Intent with the same ID

rose sleet
#

Ok, i will get back to that, now i dont know why on this webhook:

const doTest = (request, response) => {
  const sig = request.headers['stripe-signature']

  let event
  console.log('sig', sig)

  try {
    event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret)
    console.log('event', event)
  } catch (err) {
    console.error(`Error message: ${err.message}`)
    console.error(`Error stack: ${err.stack}`)
    response.status(400).send(`Webhook Error: ${err.message}`)
    return
  }

  // Handle the event
  switch (event.type) {
    case 'payment_intent.succeeded':
      const paymentIntentSucceeded = event.data.object
      // Then define and call a function to handle the event payment_intent.succeeded
      break
    // ... handle other event types
    default:
      console.log(`Unhandled event type ${event.type}`)
  }

  // Return a 200 response to acknowledge receipt of the event
  response.send()
}
#

i only can use it once i delete the try event, there is an error on this part:

    event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret)

#

errors
Response body
Webhook Error: No webhook payload was provided.

Error message: Webhook payload must be provided as a string or a Buffer (https://nodejs.org/api/buffer.html) instance representing the raw request body.Payload was provided as a parsed JavaScript object instead.
Signature verification is impossible without access to the original signed material.

simple mist
#

That should give you an example you can work off of

rose sleet
#

i think its becasue im using app.use(express.json())

simple mist
#

Anything that transforms the payload from it's raw state will cause the signature verification to fail

rose sleet
#

😒

simple mist
#

As you will see in the webhook code in the doc I shared, we use express.raw

green shuttleBOT
#

jev-webhooks-express