Stripe Webhook Netlify Page not found 404 error

PLEASE I am having a problem with my Stripe Webhook. I have created webhooks before for other projects. This particular one is confusing me.

My site name is https://terhire.com and the webhook URL is https://terhire.com/webhook. But when the checkout payment completed event is triggered, my stripe webhook dashboard returns a Netlify 404 page not found error.

I have the redirect file and I did an npm run build on my site locally before deployment. The site works fine, but the webhook doesn’t. This is confusing.

I would appreciate your help. Thanks.

This returns a 200 status

$ curl -I https://terhire.com/webhook
HTTP/2 200

However posting returns 400 status (which I might expect)

$ curl -I https://terhire.com/webhook -X POST
HTTP/2 400

Posting with empty data returns a 404 status

$ curl -i https://terhire.com/webhook -X POST -d'{}'
HTTP/2 404

The issue is the code in your webhook, not Netlify.

This is the code in my webhook

stripeRouter.post(
“/webhook”,
express.raw({ type: “application/json” }),
async (request, response) => {
const sig = request.headers[“stripe-signature”];
let event;

try {
  event = stripe.webhooks.constructEvent(
    request.rawBody,
    sig,
    endpointSecret
  );
  console.log("Webhook verified");
} catch (err) {
  response.status(400).send(`Webhook Error: ${err.message}`);
  return;
}

// Handle the event
switch (event.type) {
  case "checkout.session.completed":
    const checkoutSessionCompleted = event.data.object;
    const {
      id,
      amount_subtotal,
      amount_total,
      created,
      currency,
      customer,
      customer_details,
      payment_method_types,
      payment_status,
      shipping_details,
      total_details,
    } = checkoutSessionCompleted;

    const session = await stripe.checkout.sessions.retrieve(
      checkoutSessionCompleted.id,
      {
        expand: ["customer", "line_items.data.price.product"],
      }
    );

    await Order.create({
      session_id: id,
      user_id: session.customer.metadata.user_id,
      cart_items: session.line_items.data,
      amount_subtotal,
      amount_total,
      order_no: created,
      order_date: created,
      delivery_date: created + 14 * 24 * 60 * 60,
      currency,
      customer_id: customer,
      customer_details,
      payment_method_types,
      payment_status,
      shipping_details,
      total_details,
    });

    async function main() {
      const transporter = nodeMailer.createTransport({
        host: process.env.MAILER_HOST,
        secureConnection: true,
        port: 587,
        auth: {
          user: process.env.TERHIRE_EMAIL,
          pass: process.env.TERHIRE_PASSWORD,
        },
      });

      const info = await transporter.sendMail({
        from: `Terhire <${process.env.TERHIRE_EMAIL}>`,
        to: customer_details.email,
        subject: "Order Confirmation",
        html: emailHtml({ name: customer_details.name }),
      });

      console.log(`Message sent: ${info.messageId}`);
    }
    main();
  default:
    console.log(`Unhandled event type ${event.type}`);
}

response.send().end();

}
);

I retract my previous statement about the 404. The returned content is that of the Netlify 404 page. This only occurs when posting data.

  • A GET request to /webhook returns your home page (but blank).
  • A POST request to /webhook without data returns 400 with Bad request, missing form (I assume from your code)
  • A POST request to /webhook with data (e.g. -d '{ "some": "data" }' or -d'{}' returns the Netlify 404 page.

This still suggests (to me) it is code or configuration related. I could go making guesses all day and still not find the right guess to remedy the situation as I can’t see everything (code and configuration.) I have previously had a webhook receiving from Stripe without issues, but I wasn’t running Express but a vanilla JavaScript serverless function.

I will add though, if your code falls though to something like next() because it cannot handle the request (doesn’t meet specified conditions) that would explain why the Netlify 404 page is returned.

The weird thing is I used this same configuration for a similar project just last month.

I guess I’ll have to start over with the backend :man_shrugging: