Test webhooks on a local site
On this page
- Overview
- How do I make one?
- Which signatures does Short Leash check?
- What happens to a delivery?
- How do I test my handler without a provider?
- How do I replay a delivery after fixing my code?
- Is a webhook address safe to leave running?
- How long are deliveries kept?
- Can I use it from the terminal?
- Can I still share a whole site instead?
A webhook in Short Leash is a public HTTPS address that takes deliveries from a provider like Stripe or GitHub, checks their signatures, and forwards them to one or more of your local sites.
Webhooks are part of Short Leash Pro.
How do I make one?
Open Webhooks and choose New webhook. Fill in:
- Name, optional: lowercase letters, digits and hyphens. A name a site already uses is refused, because its address would be the same.
- Address: Random address gives a
*.trycloudflare.comaddress with no account. Your domain serves a named webhook at your sharing pattern, sostripebecomesstripe.example.dev. That address stays the same across restarts. It needs a connected domain. - Signature check: the provider and its signing secret (see below).
- Send to: one or more sites and paths, such as
northwind.testand/stripe/webhook. Or choose Just catch to record deliveries without forwarding them.
Choose Create webhook. It starts right away, and its address appears in the strip at the top of the screen with Copy. Paste that address into the provider's webhook settings.
Each webhook runs its own tunnel. A random address changes every time the webhook starts, so paste the new one into the provider after a restart, or use your domain.
Which signatures does Short Leash check?
| Provider | Header | What is signed |
|---|---|---|
| Stripe | Stripe-Signature |
{timestamp}.{raw body}, HMAC-SHA256, hex |
| GitHub | X-Hub-Signature-256 |
the raw body, HMAC-SHA256, hex |
| Shopify | X-Shopify-Hmac-Sha256 |
the raw body, HMAC-SHA256, Base64 |
| Slack | X-Slack-Signature |
v0:{timestamp}:{raw body}, HMAC-SHA256, hex |
| Standard Webhooks (Svix and others) | webhook-signature |
{id}.{timestamp}.{raw body}, HMAC-SHA256, Base64 |
| Paddle | Paddle-Signature |
{timestamp}:{raw body}, HMAC-SHA256, hex |
| Lemon Squeezy | X-Signature |
the raw body, HMAC-SHA256, hex |
| Generic HMAC | a header you choose | the raw body, with the algorithm, encoding and prefix you choose |
For providers that sign a timestamp, Short Leash accepts timestamps up to 5 minutes old by default. You can change that on the form.
Each delivery's Signature tab shows the scheme, the header, the timestamp's age, and the signature Short Leash expected next to the one that arrived. When a check fails, it says why and what to do. For example, a live-mode Stripe event checked against a test-mode secret is pointed at the live endpoint's secret. After you change the secret, choose Check again. It checks the delivery as of when it arrived, so its age doesn't count against it.
What happens to a delivery?
Short Leash applies the webhook's rules in this order:
- Reject deliveries that fail the signature check: Short Leash answers
401and your app never sees the delivery. It still shows in the list as Rejected. - Hold deliveries: Short Leash answers the provider straight away (
202, or the reply you set) and keeps the delivery. Release sends one delivery on; Release all sends every held delivery, oldest first. Hold deliveries while your site is down or while you change its code. - Just catch: the delivery is recorded and answered, and nothing is forwarded.
- Otherwise it goes to every place under Send to at once. The provider gets the first place's reply, and the others get copies. Every reply shows in the Replies tab.
Under Reply, Answer with sends a status, body and wait of your choosing instead of your app's reply. The presets test a provider's retries: 500 error, Time out after 30 s and 410 Gone. Retries of one event share its id, so they show as Attempt 2, Attempt 3 and so on.
The forwarded request also appears on the Requests screen, so you can see what your app did with it.
How do I test my handler without a provider?
Choose Send test event. Pick a webhook and a template under Start from (or Blank). You can type any Event type and edit the body. Then choose how it's signed:
- Valid signs it with your secret, now.
- Wrong secret and Expired timestamp check that your app refuses bad deliveries.
- Unsigned sends no signature at all.
Through the webhook, like a real delivery applies the webhook's check, hold and copies. Straight to your sites skips them, so your app's own signature check decides. Test events stay on your computer and never go through the tunnel.
How do I replay a delivery after fixing my code?
Choose Resend on a delivery. Short Leash sends the same body to the webhook's sites again, signed afresh with the current secret so a timestamped signature isn't too old. Edit and resend opens the same body in the test event dialog first. Resends are listed as new deliveries; the original stays.
Copy as cURL gives a command that sends the delivery to the first site. Save as fixture writes it to tests/fixtures/webhooks/<webhook>/<event>.json in that site's folder, with its headers and body, for your tests. It never overwrites an existing file. Open as call makes the delivery a call to send again with your own changes. Short Leash signs the call afresh on each send with the webhook's current secret, so an edited body still passes the site's signature check (only for calls to the webhook's own sites: its secret signs nothing else); Stop signing on its Headers tab sends the headers as they were.
Is a webhook address safe to leave running?
Tunnel traffic is untrusted, so each delivery goes through Short Leash's share listener like any shared request:
- The IP allowlist in Settings › Sharing still applies.
- The sharing password doesn't, because providers can't type one. Turn on Reject deliveries that fail the signature check instead.
Signing secrets are kept in secrets/webhooks.json, which only your account can read. They are never written to config.toml, and the app only ever sees their last four characters.
How long are deliveries kept?
Deliveries are kept in Short Leash's database, so they're still there after Short Leash restarts or updates. Each webhook keeps its last 500, for 14 days. Choose 1, 7, 14 or 30 days in Settings › Webhooks (Keep deliveries for); any number from 1 to 365 works as keep_days in the [webhooks] section of config.toml. A held delivery stays until you release it, however old it is, and removing a webhook removes its deliveries. A body over 64 KB is kept as a file beside the database. The database and those files are readable only by your account.
Choose Stop in the webhook strip when you're done. A running webhook starts again with Short Leash.
Can I use it from the terminal?
leash webhook list
leash webhook deliveries stripe --follow
leash webhook show 42
leash webhook resend 42
leash webhook release stripe
AI coding tools connected through leash mcp can list webhooks, read deliveries with their signature checks, and resend one. See the CLI reference.
Can I still share a whole site instead?
Yes. Share the site and point the provider at its shared address plus your webhook path. Deliveries then show only on the Requests screen, without signature checks, holding or resending.