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 deployWhat 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.