Provider guide

Lemon Squeezy webhooks, kept properly.

Lemon Squeezy is another merchant of record, so the same rule applies: these webhooks are how you learn that money moved. The scheme is refreshingly plain, which makes the failure modes about your side rather than theirs.

Field notes

How Lemon Squeezy behaves, and where it bites

Event name in a header, a plain hex HMAC, and custom data that only exists in the delivery.

How Lemon Squeezy sends

Lemon Squeezy POSTs JSON with the event in X-Event-Name (order_created, subscription_updated) and a hex HMAC of the raw body in X-Signature.

Where it bites

  • Custom data is passed through, not stored by you. Whatever you attached at checkout comes back in the webhook. If you did not keep the delivery, that association is gone.
  • Test and live are separate worlds. A store in test mode sends test events with their own secret, and mixing them up is the classic first-day mistake.
  • The event name is in a header. Log only the body and you lose the one field you will search on most.

The vault under it

Point a WebhookVault endpoint at Lemon Squeezy and every delivery is stored in full: headers verbatim, bodies byte-for-byte, labelled with its event name and searchable. Forward it onward to your own handler if you want the relay pattern, replay any delivery once the bug is fixed, and let a Watchdog notice the day it stops arriving.

01

Create an endpoint

Name it lemonsqueezy-orders. Turn on forwarding to your own handler if you want the vault in front of it rather than beside it.

02

Register the capture URL

Lemon Squeezy → Settings → Webhooks → add an endpoint. Paste the capture URL, set a signing secret, pick your events.

03

Keep everything

Every delivery from here on is on the shelf: searchable, replayable, and watched for the day it goes quiet.

Verify from the record, not just at the door

Lemon Squeezy signs the raw body with your signing secret and sends lowercase hex. The vault verifies every capture against it and filters on the verdict.

The vault stores the signature headers verbatim with every request, so a delivery from last month can still be checked today. Verdicts are part of Solo and up. How verification works →

captured · order_created✓ verified
# headers, stored verbatim
"X-Event-Name": "order_created"
"X-Signature": "8f3a2c41d9e6…"

{
  "meta": {
    "event_name": "order_created",
    "custom_data": { "workspace_id": "wsp_4812" }
  },
  "data": {
    "type": "orders",
    "attributes": { "status": "paid", "total": 4900 }
  }
}

Event catalogue

Lemon Squeezy webhook events you'll see

A few of the events Lemon Squeezy sends, not the full list: Lemon Squeezy's own documentation has every one. Each arrives in the vault labelled with its event name.

EventWhat it tells you
order_createdA customer completed a purchase.
order_refundedAn order was refunded.
subscription_createdA new subscription started.
subscription_updatedA subscription changed in any way, status included.
subscription_cancelledA subscription was cancelled; it stays active until the period ends.
subscription_payment_failedA renewal payment failed.

Questions

Lemon Squeezy webhook questions, answered

The three that come up most when Lemon Squeezy is wired to a new endpoint.

Does Lemon Squeezy retry failed webhooks?

Yes: a delivery that does not get a 2xx is retried a few times with growing gaps between attempts, then given up. A WebhookVault capture URL answers as soon as the event is stored, so a slow handler of yours does not use up the retries.

How do I verify X-Signature?

It is a hex HMAC-SHA256 of the raw request body, keyed with the signing secret set on the webhook. Recompute it over the bytes as received and compare in constant time. On Solo and up the vault does this at capture and puts the verdict on every row.

Where does my checkout custom data come back?

In meta.custom_data on the events for that order and its subscription. It is the link between a payment and your own user or workspace, which is why keeping the delivery matters: the vault stores the body whole, so the link survives even if your handler failed to record it.

Keep every order event.

Free tier, no card. A capture URL in a few minutes.