constructEventAsync is correct for Deno, keep that. The usual remaining causes:
- Body was parsed before verifying. You must verify the raw text:
const body = await req.text();
const sig = req.headers.get("stripe-signature")!;
const event = await stripe.webhooks.constructEventAsync(
body, sig, Deno.env.get("STRIPE_WEBHOOK_SECRET")!
);If there's a await req.json() anywhere before this, that's the bug.
-
Wrong secret. Each webhook endpoint has its own
whsec_.... Test mode and live mode are different endpoints too. The one fromstripe listenon your laptop is yet another. -
JWT check on the function. Stripe doesn't send a Supabase JWT. Deploy with
--no-verify-jwt(orverify_jwt = falsein config.toml) or Stripe gets a 401 before your code runs. You're seeing 400 so it's probably 1 or 2.