Lemon Squeezy webhooks with Node.js Express

You’ve set up your store on Lemon Squeezy and need to handle webhook events.

Webhook events can be used to keep track of e.g.

  • Orders
  • Subscriptions
  • Payments
  • License Keys

Webhooks on Express.js basic JavaScript example

Let’s have a look how you can handle Lemon Squeezy’s webhooks using Express on Node.js.

The example requires two installed packages:

npm install dotenv express

Also you need the signing secret, which you get when setting up the webhook endpoint at your Lemon Squeezy dashboard.

// Place your Lemon Squeezy endpoint signing secret in your .env file
// e.g. SIGNING_SECRET=MySecret
require('dotenv').config();

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

const app = express();

app.post('/webhook', express.raw({ type: 'application/json' }), async (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}`);
});

Look up the contents of different webhook events at Lemon Squeezy docs.

Katso myös