Can someone fake a payment in your app?

Your Stripe webhook is a public address that turns messages into paid accounts. Paste the code and see whether it checks those messages really came from Stripe.

  • Catches missing and broken signature checks
  • Flags leaked secrets, repeated events and cancelled plans
  • Runs in your browser, nothing is sent

Usually in app/api/stripe/webhook/route.ts, pages/api/webhook.ts or supabase/functions/stripe-webhook/index.ts. Not sure? Ask your AI tool: "Which file handles Stripe webhooks?"

Runs in your browser. Nothing you paste is sent anywhere.

How fake payments get through

No signature check. A webhook is just a URL. Anyone can send it a made-up "checkout completed" event with their own user id. Without a signature check, your app believes it and hands out Pro.

A check that was switched off. AI tools often read the body with req.json() and then check the signature. That always fails, because the signature covers the exact text Stripe sent. The next "fix" is to comment the check out.

A leaked signing secret. A whsec_ secret written into the code, or kept in a variable starting with NEXT_PUBLIC_ or VITE_, lets anyone sign fake events that pass the check.

Not a fake, still a loss. Stripe sends some events twice, so credits get added twice. And a handler that never hears about cancellations lets people keep Pro after they stop paying.

A safe webhook, step by step

  1. Read the body as raw text with await req.text() (or express.raw() in Express).
  2. Check it with stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET). On Supabase Edge Functions, use constructEventAsync.
  3. If the check fails, return a 400 and do nothing else.
  4. Record the event id. If you have seen it before, stop.
  5. Give access on checkout.session.completed once the payment status is paid, and take it away on customer.subscription.deleted.
  6. Paste it here: every check should say Good.

Questions

Why can't Stripe just protect me from fake events?
Stripe signs every event it sends, but it cannot stop other people from sending requests to your URL. Only your code can tell the difference, by checking the signature with your webhook secret before it acts.
Is it safe to paste my webhook code here?
Yes. The checker runs entirely in your browser: nothing you paste leaves your computer. If your code contains a secret key, the checker shows it masked and tells you to roll it, because a key in code is already in your Git history.
If every check passes, am I safe?
It means the common mistakes are not in the code you pasted. It reads text and cannot run your app, so it cannot see helpers in other files or what your database does. Also check that access is only ever given in the webhook, never on the success page.