#moez - webhook

1 messages · Page 1 of 1 (latest)

teal patio
#

Hey there, can we chat in this thread?

#

Would you mind moving the snippet in here please? I'll get back to you as soon as i can

fading summit
#

ok

#
exports.getCheckoutStripe = async(req, res, next) => {
  const travel = await Travel.findById(req.params.travelId);
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    success_url: `${req.protocol}://${req.get('host')}/my-booked-travels`,
    cancel_url: `${req.protocol}://${req.get('host')}/travel/${travel.slug}`,
    customer_email: req.user.email,
    client_reference_id: req.params.travelId,
    line_items: [
      {
        name: `${travel.name} Travel`,
        description: travel.summary,
        images[
`${req.protocol}://${req.get('host')}/img/travels/${travel.imageCover}`
        ],
        amount: travel.price * 100,
        currency: 'usd',
        quantity: 1
      }
    ]
  });
  res.status(200).json({
    status: 'success',
    session
  });
});
const bookingBasedCheckout = async (session) => {
  try {
    const travel = session.client_reference_id;
    const user = (await User.findOne(
      { email: session.customer_email })
    ).id;
    const price = session.line_items[0].amount / 100;

    await Booking.create({ travel, user, price });
  } catch (error) {
    console.log(error.message)
  }
}
exports.webhookCheckout = (req, res) => {
  const signature = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      signature,
      process.env.STRIPE_WEBHOOKS_SECRET
    );
  } catch(error) {
    return res.status(400).send(`error: ${error.message}`)
  }
  if (event.type === 'checkout.session.completed') {
    bookingBasedCheckout(event.data.object);
  }
  res.status(200).json({ recieved: true })
}
#

My issue is I'm able to create a new booking with every successful payment

#

so I'm already in prod mode

#

I print my logs in terminal to see what is going on and I find that the response to the webhooks was with 400 status code

#
2022-02-15T20:29:24.843700+00:00 heroku[router]: at=info method=POST path="/webhook-checkout" host=goaheadtravel.herokuapp.com request_id=a1092076-de76-4a05-be25-c48c5f5a792d fwd="54.187.174.169" dyno=web.1 connect=0ms service=3ms status=400 bytes=814 protocol=https
teal patio
#

Was this endpoint working in testmode?

#

the webhook handler endpoint i mean, with the signature verification

#

Do you have any example event IDs I can review?

fading summit
#

I used the test mode already

teal patio
#

Ok, and was it working there?

fading summit
#

"cs_test_a1gYZnIzXd6cML1EFcJq3Cmc7QzjR4Qe7oLAoN9NY3GHa38Bex6TgXY1DK",

#

I grab the id above from a failed log

teal patio
#

I mean was this webhook endpoint working in test mode like you expected?

#

Were you able to create the booking from the events in test mode?

#

Can you share some specific failed event delivery IDs like evt_1234? or successful ones form test mode?

fading summit
#

I used a the test-mode from the beginning, but the app is in production mode

teal patio
#

Can you copy one of those event IDs here?

#

It looks like the delivery is still pending in test mode, too

#

Which likely means this was not working in test either

fading summit
#

ok

teal patio
#

I'd suggest exploring further in test mode to understand what is failing, and where

fading summit
#
{
  "object": {
    "id": "cs_test_a1bCZIN7IPMQWMA4A6XbtyL1Jb3DePqmoWojlKyGAKdMnkhHemUFYBQJNV",
    "object": "checkout.session",
    "after_expiration": null,
    "allow_promotion_codes": null,
    "amount_subtotal": 39700,
    "amount_total": 39700,
    "automatic_tax": {
      "enabled": false,
      "status": null
    },
    "billing_address_collection": null,
    "cancel_url": "https://goaheadtravel.herokuapp.com/travel/venice-by-night",
    "client_reference_id": "5c88fa8cf4afda39709c2951",
    "consent": null,
    "consent_collection": null,
    "currency": "usd",
    "customer": "cus_L9rwYNwkJjGLGs",
    "customer_creation": "always",
    "customer_details": {
      "email": "eliana@example.com",
      "phone": null,
      "tax_exempt": "none",
      "tax_ids": [
      ]
    },
    "customer_email": "eliana@example.com",
    "expires_at": 1645045439,
    "livemode": false,
    "locale": null,
    "metadata": {
    },
    "mode": "payment",
    "payment_intent": "pi_3KTYBnA1H3VpG3Rz1RGzUSHH",
    "payment_link": null,
    "payment_method_options": {
    },
    "payment_method_types": [
      "card"
    ],
    "payment_status": "paid",
    "phone_number_collection": {
      "enabled": false
    },
    "recovered_from": null,
    "setup_intent": null,
    "shipping": null,
    "shipping_address_collection": null,
    "shipping_options": [
    ],
    "shipping_rate": null,
    "status": "complete",
    "submit_type": null,
    "subscription": null,
    "success_url": "https://goaheadtravel.herokuapp.com/my-booked-travels",
    "total_details": {
      "amount_discount": 0,
      "amount_shipping": 0,
      "amount_tax": 0
    },
    "url": null
  }
}
teal patio
#

Usually in Node a common issue is modification of the raw request body before verifying signature

#

Those event lines you see with the "Pending" message

#

Click in to one of them, and you should be able to see your server response body shown

fading summit
#
error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
teal patio
#

Is your server using express for serving the endpoints, and do you have json body parsing enabled?

fading summit
#

yes, but I used the express.raw in post request before json body parsing enabeling

#
// use the stripe webhook in order to create a new booking travel
app.post(
  '/webhook-checkout',
  express.raw({ type: 'application / json' }),
  bookingController.webhookCheckout
);

// Body parser, reading data from body into req.body
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
app.use(cookieParser());
teal patio
#

Hmm ok, then you'll need to confirm all the inputs to constructEvent with some additional logging.

#

Making sure you have the raw request body (it should contain extra whitespace), the signature, and the signing secret

#

It's also easy to mix up signing secrets if you're testing multiple endpoints or live and test, as those secrets are specific to each endpoint

#

Looking at your account, you only have a test mode endpoint configured

#

So in test mode you'd expect the signing secret to be whsec_T7...Cgrf

#

but in order to support live mode you'd need to create a live mode endpoint in your dashboard, which will have a new/unique signing secret