DEV Community

Cover image for Handle Lemon Squeezy webhooks with Node.js Express
Juha
Juha

Posted on

Handle Lemon Squeezy webhooks with Node.js Express

You’ve set up your store on Lemon Squeezy and need to handle webhook events? Let's look at a quick 'n simple NodeJS example.

What are webhooks good for?

Webhook events are instrumental in tracking various elements such as:

  • Orders
  • Subscriptions
  • Payments
  • License Keys
  • And more...

In essence, webhooks are about efficiency and responsiveness. They provide a way for your Lemon Squeezy store to communicate with your server or other applications in real-time.

Webhooks cut down on the need for manual checks and processing. This real-time data transfer enables systems to react instantly to events as they occur, which is essential for a seamless and automated online venture.

Example of Webhooks on Node & Express

Let's look at what the webhook listener generally looks like.

This example requires two installed packages:

npm install dotenv express
Enter fullscreen mode Exit fullscreen mode

The listener needs your signing secret, which you get when setting up the webhook endpoint at your Lemon Squeezy dashboard. Place the signing secret into your .env file.

echo "SIGNING_SECRET=MySecret" >>.env
Enter fullscreen mode Exit fullscreen mode

Now the actual webhook listener with ExpressJS:

require('dotenv').config();

const crypto = require('crypto');
const express = require('express');

const app = express();

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
    // Make sure the request is actually from Lemon Squeezy
    //
    const hmac = crypto.createHmac('sha256', process.env.SIGNING_SECRET);
    const digest = Buffer.from(hmac.update(req.body).digest('hex'), 'utf8');
    const signature = Buffer.from(req.headers['x-signature'] || '', 'utf8');

    let sigOK = false;
    try {
        sigOK = crypto.timingSafeEqual(digest, signature);
    } catch (err) {
        console.log("ERROR: timingSafeEqual: " + err);
    }

    if (! sigOK) {
        console.log("ERROR: Invalid signature");
        res.status(400).send("ERROR: Invalid signature");
        return;
    }

    // Parse the webhook's data as JSON
    const event = JSON.parse(req.body.toString());

    console.log(`${event.meta.event_name} webhook received`);

    // Explore the event object's contents, and do your thing with it
    console.log(event);

    res.send();
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server listening on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Look up the data included in different webhook events from Lemon Squeezy docs.

This was a quick reference designed for developers who need a refresher on integrating Lemon Squeezy webhooks with Node.js. It's the nuts and bolts of the setup process to get you started.

Top comments (1)

Collapse
 
lirantal profile image
Liran Tal

Thanks for sharing!

If anyone fancy a Firebase Functions write-up on Fastify and getting the Lemon Squeezy webhook to work, read how I solved it: lirantal.com/blog/http-webhooks-fi...