Verify signatures
Each delivery carries a header like this:
v1 is an HMAC-SHA256, in hexadecimal, of {t}.{raw body} with your endpoint's secret. Reject the delivery if no v1 matches or if t is more than 5 minutes from your clock.
With the SDK
constructEvent verifies the signature and returns the parsed event, typed by its type. await Lelemon.webhooks.verifyHeader(payload, header, secret) only verifies: it returns nothing and throws LelemonSignatureVerificationError when the signature, the timestamp or the secret do not match. Both are asynchronous and accept { toleranceSeconds }, which defaults to 300.
Without the SDK
Always use the raw request body. A body that was parsed and serialized again will not match.
Rotating the secret
POST /v2/webhook-endpoints/{id}/rotate-secret returns a new secret. For 24 hours both secrets sign, and the header carries two v1 values. Accept either until you have deployed the new one.