Shanu k k
Shanu k k

Reputation: 1285

Stripe webhook -Webhook Error: Webhook payload must be provided as a string or a Buffer

I am trying to console a message when payment is success using stripe for that i am using webhooks.

const stripe = require('stripe')('sk_test_'); // Replace with your actual key

const handleWebhook = async (req, res) => {
    let event;
    
    try {
        const sig = req.headers['stripe-signature'];
        // Use req.body directly since it's raw
        event = stripe.webhooks.constructEvent(req.body, sig, 'whsec_code'); 
    } catch (err) {
        console.error(`Webhook Error: ${err.message}`);
        return res.status(400).send(`Webhook Error: ${err.message}`);
    }

    console.log(event.type);
    switch (event.type) {
        case 'checkout.session.completed':
            const session = event.data.object;
            console.log('Checkout session completed:', session.id);
            if (session.payment_status === 'paid') { alert("hii")
                console.log('PaymentIntent was successful!');
                const updatedValues = JSON.parse(session.metadata.updatedValues);
                console.log("updatedValues is", updatedValues);
            }
            break;

And session.payment_status === 'paid' i need to test whether webhook is working or not.so i just alert a message.but i am getting

Webhook Error: 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.

my app.js

gsrApp.use((req, res, next) => {
  console.log(`Incoming request size: ${JSON.stringify(req.body).length} bytes`);
  next();
});

and router i have

routerV2.post('/webhook', express.raw({ type: 'application/json' }), handleWebhook);

Thanks in advance

Upvotes: 1

Views: 210

Answers (2)

Yuvaraj M
Yuvaraj M

Reputation: 4618

It's because of app.use(express.json()); code.

So the simplest solution would be moving the webhook route before app.use(express.json());

If you can't do that then try this

app.js

app.use(
    express.json({
        verify(req, res, buf, encoding) {
            if (req.path.includes('webhook')){
                req.rawBody = buf.toString(); // sets raw string in req.rawBody variable
            }
        }
    })
);

webhook handler

const handleWebhook = async (req, res) => {
let event;

try {
    const sig = req.headers['stripe-signature'];
    // USE req.rawBody which is created specifically for this route
    event = stripe.webhooks.constructEvent(req.rawBody, sig, 'whsec_code');  
} catch (err) {
    console.error(`Webhook Error: ${err.message}`);
    return res.status(400).send(`Webhook Error: ${err.message}`);
}

console.log(event.type);
switch (event.type) {
    case 'checkout.session.completed':
        const session = event.data.object;
        console.log('Checkout session completed:', session.id);
        if (session.payment_status === 'paid') { alert("hii")
            console.log('PaymentIntent was successful!');
            const updatedValues = JSON.parse(session.metadata.updatedValues);
            console.log("updatedValues is", updatedValues);
        }
        break;

Finally you don't need express.raw({ type: 'application/json' }), since we are doing that

router

routerV2.post('/webhook', handleWebhook);

Upvotes: 1

orakaro
orakaro

Reputation: 1981

This is a common error, where you web framework might have accidentally (or unintentionally) interfered the request body Stripe sent. A rule of thumbs is Stripe SDK expects the exact raw body from the incoming HTTP request.

It worths following the exact Stripe example code, or look through this Github issue for webhook on Node. Common gotchas is watching out bodyParser or use a rawBody. Also if you use AWS lambda, you might need some Body Mapping Template.

Upvotes: 0

Related Questions