PinPiguin
PinPiguin

Reputation: 477

Next.js Stripe webhook Undefined function problem

I am trying to make a stripe webhook in NextJS app and want it to write some data to Firebase Firestore. But stripe.webhook.constructEvent comes undefined, despite having all items in place.

I use Stripe CLI like follows:

stripe listen --forward-to localhost:3000/api/webhook

The output is as follows:

2022-12-20 16:57:18   --> charge.succeeded [evt_3MH8BsL1z8EG1fYg1HgxX6Fm]
2022-12-20 16:57:18   --> payment_intent.succeeded [evt_3MH8BsL1z8EG1fYg1ExIxxZ7]
2022-12-20 16:57:18   --> checkout.session.completed [evt_1MH8BuL1z8EG1fYgo2lLPZkC]
2022-12-20 16:57:18   --> payment_intent.created [evt_3MH8BsL1z8EG1fYg1ezapckU]
2022-12-20 16:57:18  <--  [400] POST http://localhost:3000/api/webhook [evt_3MH8BsL1z8EG1fYg1HgxX6Fm]
2022-12-20 16:57:18  <--  [400] POST http://localhost:3000/api/webhook [evt_3MH8BsL1z8EG1fYg1ExIxxZ7]
2022-12-20 16:57:18  <--  [400] POST http://localhost:3000/api/webhook [evt_1MH8BuL1z8EG1fYgo2lLPZkC]
2022-12-20 16:57:18  <--  [400] POST http://localhost:3000/api/webhook [evt_3MH8BsL1z8EG1fYg1ezapckU]

In app console, however is the following error:

Error Cannot read properties of undefined (reading 'constructEvent')
Error Cannot read properties of undefined (reading 'constructEvent')
Error Cannot read properties of undefined (reading 'constructEvent')
Error Cannot read properties of undefined (reading 'constructEvent')

Here is webhook.js code:

import { buffer } from "micro";
import * as admin from "firebase-admin";

const serviceAccount = require("../../../credentials.json");

const app = !admin.apps.length
  ? admin.initializeApp({
      credentials: admin.credential.cert(serviceAccount),
    })
  : admin.app();

//connect to stripe

const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);

const endpointSecret = process.env.SIGNING_SECRET;

const fulfillOrder = async (session) => {
  console.log("Fill Order");
  return app
    .firestore()
    .collection("users")
    .doc(session.metadata.email)
    .collection("orders")
    .doc(session.id)
    .set({
      amount: session.amount.total / 100,
      amount_shipping: session.total_details.amount_shipping / 100,
      images: JSON.parse(session.metadata.images),
      timestamp: admin.firestore.FieldValue.serverTimestamp(),
    })
    .then(() => {
      console.log(`Success: Order ${session.id} added to db `);
    });
};

export default async (req, res) => {
  if (req.method === "POST") {
    const requestBuffer = await buffer(req);
    const payload = requestBuffer.toString();
    const sig = req.headers["stripe-signature"];
    //console.log("REQBUF", requestBuffer);
    //console.log("PAYLOAD", payload);
    //console.log("SIG", sig);
  }

  let event;
  //verify that event came from stripe
  try {
    event = stripe.webhook.constructEvent(payload, sig, endpointSecret);
  } catch (error) {
    console.log("Error", error.message);
    return res.status(400).send(`Webhook error: ${error.message}`);
  }

  //handle checkout session
  if (event.type === "checkout.session.completed") {
    const session = event.data.object;
    return fulfillOrder(session)
      .then(() => res.status(200))
      .catch((error) =>
        res.status(400).send(`Webhook error: ${error.message}`)
      );
  }
};

export const config = {
  api: {
    bodyParser: false,
    externalResolver: true,
  },
};

I checked that constructEvent function has none of the arguments empty. However it is always UNDEFINED.

I am out ideas. Please help.

Upvotes: 0

Views: 644

Answers (1)

pgs
pgs

Reputation: 1181

It appears that there is a typo on this line of code event = stripe.webhook.constructEvent, instead it should be event = stripe.webhooks.constructEvent as shown on the API document here.

Also, it looks like you're using a library called micro, Stripe's signature verification requires you to pass the raw request body. Many libraries modify the body by default so you might see an issue here as well. To resolve this, you'd want to make sure that you pass the raw request body.

Upvotes: 1

Related Questions