Verify x-signature before trusting event fields
Only derive idempotency keys after raw-body signature verification. Bad signatures should return 400, not run fulfillment or create durable keys.
Lemon Squeezy duplicate webhook retry
Duplicate webhook delivery is not a bug. Lemon Squeezy can retry after timeouts, 5xx responses, network failures, or uncertain delivery. Your handler must prove it can process a paid event once without sending duplicate downloads, license keys, emails, or access grants.
Only derive idempotency keys after raw-body signature verification. Bad signatures should return 400, not run fulfillment or create durable keys.
Write lemonsqueezy:order_created:order_id or an equivalent unique key before sending email, downloads, license keys, or account access.
Replay the same paid fixture repeatedly. The first request should fulfill; later duplicates should return success and skip side effects.
If a paid order was already processed, return 2xx and skip duplicate fulfillment. Do not make Lemon Squeezy keep retrying an event that your system already handled.
Missing or invalid x-signature, wrong product, unsupported event type, or malformed payload should fail cleanly without writing fulfillment state.
If a verified paid event cannot be durably stored or delivered, return 500 only after your handler can retry without duplicate side effects.
Unknown events should produce a reviewable report, not a crash. Record the event name and safe metadata without exposing customer data or secrets.
Keep the idempotency guard close to the first durable write. The exact database API can vary, but the contract should stay stable.
export async function handleLemonPaidOrder(event) {
const orderId = event.data?.id;
const eventName = event.meta?.event_name;
const key = `lemonsqueezy:${eventName}:${orderId}`;
const inserted = await insertIdempotencyKey(key);
if (!inserted) {
return { ok: true, duplicate: true };
}
await deliverPrivateDownload(event);
await grantBuyerAccess(event);
await sendDeliveryEmail(event);
return { ok: true, duplicate: false };
}
order_created fixture that returns 2xx.duplicate: true.Safety boundary: use fake payloads and redacted logs in public reports. Never paste Lemon Squeezy API keys, webhook signing secrets, private checkout links, customer data, database URLs, or full live order payloads into shared debugging artifacts.