Skip to main content

Overview

A complete, copy-pasteable receiver for External Webhooks. Every delivery is HMAC-signed, so verification is the same on every endpoint - there is no unauthenticated mode to handle. Verification is a handful of standard-library calls in any language. There is no Leen SDK to install and nothing to import.
Verify against the raw request body. Leen signs the exact bytes it sends. If your framework parses the JSON and you re-serialize it before hashing, key order and whitespace change, the digest changes, and every signature check fails. Each example below reads the raw body first, deliberately.

The two rules that matter

  1. Compare in constant time. Use hmac.compare_digest (Python), crypto.timingSafeEqual (Node), or hmac.Equal (Go) - never ==. A plain string comparison returns faster the earlier it finds a mismatched byte, which leaks the expected signature a byte at a time to anyone willing to measure.
  2. Check the digest before the timestamp. Then a replayed request is reported as a replay rather than as a bad secret, and you can tell the two apart when debugging.

HMAC

The signature header is v0=sha256=<hex digest>, and the signed payload is {timestamp}.{raw body}.

Testing it locally

1

Expose your receiver

Leen only delivers to public HTTPS addresses, so a local port needs a tunnel:
2

Register the tunnel URL

In the portal, go to Settings → Webhooks → Add Endpoint and register the tunnel address (https://<subdomain>.ngrok.app/leen/webhooks), subscribed to at least webhook.ping. Full walkthrough: Registering an endpoint.Copy the signing secret into LEEN_SIGNING_SECRET when it is shown - that is the only time you will see it.
3

Ping it

Hit Send test on the endpoint. That queues a webhook.ping to your tunnel.
4

Confirm what Leen saw

Open the endpoint and read the Deliveries table. Every attempt records your status code and a snippet of your response body, so a rejected signature shows up there as a 401 without you adding any logging on your side.

Exercising the retry path

To confirm your retry handling, return a 500 from the receiver for the first few requests. Leen makes 5 attempts - roughly 10s, 30s, 90s, then 4.5m apart - and every one carries the same X-Leen-Event-Id, which is exactly the duplicate case your deduplication has to survive. Returning a 400 or 401 instead ends the delivery immediately with no retry, which is the behaviour to expect while a signature check is misconfigured.