Receive Lemon Squeezy Webhooks in Next.js

Learn how to receive Lemon Squeezy webhooks in Next.js.


In this example we will create a very simple API endpoint in Next.js to receive Lemon Squeezy webhook events. This endpoint will check the webhook signature to make sure it’s a legitimate request from Lemon Squeezy.

Create a new Next.js project

First, create a new Next.js project:

npx create-next-app@latest my-nextjs-app

Read the Next.js installation docs for more information.

In this example we have opted-in to use src folder.

Create a route handler

Create a new route handler in Next.js in the src/app/api/webhooks folder. The file should be called route.ts:

import { NextRequest } from "next/server";
 
export async function POST(request: NextRequest) {}

This endpoint will be available on the api/webhooks route.

Verify the webhook signature

The first thing the webhook handler should do is verify the webhook signature. This ensures that the webhook request is legitimate and not from a malicious source. We do this by veryfing the X-Signature header.

import crypto from "node:crypto";
import { NextRequest, NextResponse } from "next/server";
 
export async function POST(request: NextRequest) {
  const secret = process.env.LEMONSQUEEZY_WEBHOOK_SECRET;
 
  if (!secret) {
    return NextResponse.json("LEMONSQUEEZY_WEBHOOK_SECRET not set in .env", { status: 400 });
  }
 
  const rawBody = await request.text();
  const signature = Buffer.from(
    request.headers.get("X-Signature") ?? "",
    "hex"
  );
 
  if (signature.length === 0 || rawBody.length === 0) {
    return NextResponse.json("Invalid request", { status: 400 });
  }
 
  const hmac = Buffer.from(
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex"),
    "hex"
  );
 
  if (!crypto.timingSafeEqual(hmac, signature)) {
    return NextResponse.json("Invalid request", { status: 400 });
  }
 
  // The request is valid, parse the data here
 
  return NextResponse.json("OK", { status: 200 });
}

Read more about verifying signed requests.

Parse the webhook data

After verifying the webhook signature, you can parse the webhook data. The webhook data is sent as JSON in the request body.

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

Create a webhook in Lemon Squeezy

Now we need to create a webhook in Lemon Squeezy. Go to Settings » Webhook and create a new webhook. Use the URL of your app. The webhook endpoint will be at /api/webhook.

Then select the events you want to be sent to your webhook route. If you’re selling digital products, maybe all you need is order_created. If you’re selling subscriptions, you can enable subscription_* events.

Add environment variables

As a final step, add LEMONSQUEEZY_WEBHOOK_SECRET to your .env file, and set the Lemon Squeezy webhook secret, that you added when created the webhook, as the value.

LEMONSQUEEZY_WEBHOOK_SECRET=add_your_webhook_secret_here

That’s it! You now have a webhook handler in Next.js that can receive Lemon Squeezy webhook events.


Was this page helpful?