← Templates

A Stripe webhook endpoint that checks every signature

A Stripe webhook endpoint that checks every request's signature with the Stripe SDK and refuses anything Stripe didn't sign. Your code goes in one switch, with each event already typed.

You want Stripe's events, not requests from whoever finds the URL

Your webhook URL is public, so anyone can send it a fake payment event. This endpoint checks Stripe's signature on every request, and your code only sees the ones that pass.

The whole template is public. Read it before you trust it.

Or scaffold it

$ npx wawesome init --template stripe-webhook
$ npx wawesome deploy

What you get

A Function called stripe-events, all in src/index.ts. It checks the body, exactly as Stripe sent it, with the Stripe SDK before it parses anything:

event = await Stripe.webhooks.constructEventAsync(
  payload,
  request.headers.get("stripe-signature") ?? "",
  secret,
  undefined,
  cryptoProvider,
);

A signature that’s wrong, missing or older than five minutes gets a 400. A good event goes to handleEvent, a switch on event.type, where each case’s event.data.object already has the right Stripe type. It starts with checkout.session.completed, payment_intent.succeeded, payment_intent.payment_failed and customer.subscription.deleted.

Run it

npx wawesome init --template stripe-webhook

It offers to log you in if you aren’t. Then it asks for a Function name, stripe-events by default, and an App slug. If you haven’t deployed yet, it offers to change your workspace address, which locks at your first deploy. All three are in the URL you give Stripe, so choose them now.

It asks for STRIPE_WEBHOOK_SECRET last. Leave it blank. Stripe only makes it once the endpoint exists. init deploys and prints your URL. Add that URL in Stripe Dashboard → Developers → Webhooks, then store the signing secret it shows you:

npx wawesome env set STRIPE_WEBHOOK_SECRET whsec_... --secret

Until you do, every request gets a 500. Send a test event from Stripe and watch it arrive with npx wawesome logs --follow.

What to change first

The cases in handleEvent. Each one only logs. Stripe retries any answer that isn’t a 2xx, and one that comes too late. Save the event, answer, and keep slow work out of the request.

What it doesn’t do

It doesn’t skip duplicates. Stripe can send the same event twice, and in any order. Save event.id in a database of your own and skip one you’ve seen. It doesn’t call the Stripe API, so it holds no API key.

  • stripe
  • webhook
  • payments
  • typescript

Ready in about a minute

Sign in with GitHub, deploy, and get a public HTTPS endpoint.

Deploy this template