How to send webhook events to LogSnag

Dan Rowden  ·  May 25, 2023

LogSnag has an official plugin for Lemon Squeezy, which means you don't have to follow this tutorial to show Lemon Squeezy events in LogSnag.
This tutorial is useful as an example of how to implement Lemon Squeezy webhooks in your application, or if you want to control how your event data is displayed in LogSnag.

LogSnag is a tool for monitoring events in applications, with web, mobile and desktop apps to keep track of what's happening.

This tutorial explains how to create a simple Next.js application to receive store updates from Lemon Squeezy and send them to LogSnag, so you can be alerted on your computer or phone (or even your smartwatch!) when you get new orders or subscriptions.

Bonus: You can publish this application online for free and with no coding required by deploying to Vercel. Read on for more details.

How it works

In this example we will create a very simple endpoint built with Next.js to receive webhook events. This endpoint does three things:

  • Checks the webhook signature to make sure it's a legimate request from Lemon Squeezy
  • Transforms the full webhook event into a data structure that LogSnag can ingest
  • Sends the data to LogSnag

LogSnag offers a very simple API for creating events. For each webhook event in Lemon Squeezy, we transform the data and then send it to a specific "channel" in LogSnag, where it's possible to collect and track different events.

Create the webhook endpoint in Next.js

The first step is to create a Next.js app. Open Terminal or a similar command line application. Navigate to where you want the project folder to be created and type the following command to create a new project and file structure:

npx create-next-app@latest

Read the Next.js installation docs for more information.

In the app directory, create a new folder webhook and then create a route.ts file. This endpoint will be available at https://localhost:3000/webhook.

In app/route.ts create a POST Route Handler which will accept all webhook events sent by Lemon Squeezy.

export async function POST(request: Request) { // Do something }

The first thing the code needs to do is to check that the request originated from Lemon Squeezy. We do this by verifying the X-Signature header:

export async function POST(request: Request) { const crypto = require('crypto'); const rawBody = await request.text() const secret = process.env.LEMONSQUEEZY_WEBHOOK_SECRET; const hmac = crypto.createHmac('sha256', secret); const digest = Buffer.from(hmac.update(rawBody).digest('hex'), 'utf8'); const signature = Buffer.from(request.headers.get('X-Signature') || '', 'utf8'); if (!crypto.timingSafeEqual(digest, signature)) { throw new Error('Invalid signature.'); } }

Read more about verifying signed requests

Then we can start grabbing top-level data from the request:

const data = JSON.parse(rawBody) const eventName = data['meta']['event_name'] const obj = data['data']['attributes'] const objId = data['data']['id']

And now we can process the webhook event and create data ready to send to LogSnag.

We need to install the LogSnag package, so go back to your command line application and run:

npm install --save logsnag

Add the following to the top of your app/route.ts file:

import { LogSnag } from 'logsnag'; const logsnag = new LogSnag({ token: process.env.LOGSNAG_TOKEN, project: process.env.LOGSNAG_PROJECT })

Then you can start processing each event type and send it to LogSnag:

var eventData switch (eventName) { case 'order_created': eventData = { channel: process.env.LOGSNAG_CHANNEL, event: "New order", description: `${obj['first_order_item']['product_name']} (${obj['first_order_item']['variant_name']})\n${obj['subtotal_formatted']} (\+${obj['tax_formatted']} tax)\nOrder #${obj['order_number']} • ${obj['user_email']} • ${obj['user_name']}\n[View order](https://app.lemonsqueezy.com/orders/${obj['identifier']})`, icon: "💳", notify: true, tags: { email: obj['user_email'], 'customer-id': obj['customer_id'] }, parser: "markdown" } break; case 'subscription_created': ... } await logsnag.publish(eventData)

The last step is to return a 200 response so that Lemon Squeezy knows the webhook was accepted successfully (the webhook will be resent if a different HTTP code is returned).

return new Response('OK')

And you're done coding!

You can see a full code example on Github at github.com/lmsqueezy/logsnag-nextjs.

You can fork this code and publish your own self-hosted webhook endpoint, or use the one-click Vercel deployment (see below).

Create a webhook in Lemon Squeezy

Now we need to create a webhook in Lemon Squeezy so that the system will send notifications of certain events to your app.

Go to Settings > Webhook and create a new webhook. Use the URL of your app. The webhook endpoint will be at /webhook.

Then select the events you want to be sent to LogSnag. If you're selling digital products, maybe all you need is order_created. If you're selling subscriptions, you can enable any of the subscription_* events.

Add environment variables

As a final step, create an .env file in the app's root directory to store your variables for each service.

The webhook secret is what you added when creating the webhook in Lemon Squeezy. The LogSnag API token can be created in your LogSnag settings.

LEMONSQUEEZY_WEBHOOK_SECRET=a_random_string LOGSNAG_TOKEN=api_token LOGSNAG_PROJECT=name_of_project LOGSNAG_CHANNEL=name_of_channel

Deploy on Vercel

You can deploy this production-ready app to Vercel with a single click.

This means you can set up a connection between Lemon Squeezy and LogSnag without coding and for free on Vercel's Hobby plan.

Head to the repo on Github, read the instructions and click the Deploy button.

In minutes you'll be ready to view Lemon Squeezy events in your LogSnag apps.

Sync customer data to Fernand