Vibe Unstuck

Free fixes / Card 7

Stripe webhook broken in production

Symptom

Checkout looks fine (or redirects "success"), but entitlements never unlock, customers get charged twice, or Stripe Dashboard shows failed webhook deliveries. Local CLI / Stripe CLI tests often still pass.

Plain English

The browser success page is not proof of payment. Stripe must hit your server webhook with a signed event. On deploy, AI-built apps usually miss one of: the live webhook URL, the signing secret in host env, verifying against the raw request body, or idempotency when Stripe retries. That is how you get free lifetime access, silent no-access, or double charges.

Checklist

  1. In Stripe Dashboard, open Developers → Webhooks and confirm a live endpoint points at your production route (https, not localhost).
  2. Put the endpoint signing secret in the host env (for example STRIPE_WEBHOOK_SECRET). Redeploy after saving.
  3. Verify with Stripe's library using the raw body (constructEvent), not a parsed JSON object. Many frameworks need a raw-body route flag.
  4. Treat each event.id as once-only (store processed ids) so retries do not double-grant or double-charge.
  5. Do not mark the order paid from the browser redirect alone. Unlock access only after a verified webhook event.
  6. Confirm you never put the Stripe secret key in client code or a NEXT_PUBLIC_ / VITE_ variable.

Paste-ready fix prompt

Paste this into Cursor, Claude, Copilot, Lovable, Bolt, or whichever coding agent you use.

My Stripe checkout seems to work in the browser but production entitlements / orders are wrong (missing unlock, double charge, or failed webhooks in Stripe Dashboard). Treat this as a webhook wiring problem first.

1. Find every Stripe webhook route and show whether it verifies signatures with constructEvent (or equivalent) on the raw request body.
2. List exact production env vars I need (publishable key, secret key, webhook signing secret) and which must stay server-only.
3. Add idempotency keyed on Stripe event.id so retries cannot double-grant.
4. Stop marking payments complete from the success redirect alone; unlock only after a verified webhook.
5. Give me the exact live webhook URL path to paste into Stripe Dashboard and a 5-step test with Stripe CLI or Dashboard resend.
6. Do not rewrite the product. Only make payment confirmation production-safe.

Still stuck?

This card covers the most common version of this break. If yours is different, send it in for a custom pass.

Get an unstuck pass