Matt Turley, Continuum. Updated November 5, 2026.
For founders whose payment succeeds in Stripe but nothing happens in the app afterwards: no access granted, no order created, no email sent.
Stripe is almost always sending the event; your server is refusing it or never receives it. Open the delivery log for your endpoint in the Stripe Dashboard. A redirect, a 401 from deployment protection or auth middleware, a 400 from a failed signature check, or a 500 from your handler each point to a different fix.
"Not firing" covers three different failures, and the fix depends on which one you have. Either Stripe never tried to send the event, or it tried and your server never received it, or your server received it and rejected it. The delivery log for your webhook endpoint in the Stripe Dashboard tells you which in about a minute, before you read any code.
Webhooks matter more than they look. A checkout success page is only a browser redirect: if the customer closes the tab, or the redirect fails, nothing runs. The webhook is the only signal that is sent to your server by Stripe itself, which is why access, orders and receipts should be driven by it.
AI-generated webhook handlers tend to work against the Stripe CLI on a laptop and then fail in production for reasons the CLI hides: a different signing secret, a route that auth middleware now protects, or a body that was parsed before it was verified.
How to tell Test mode and live mode have separate endpoints, separate events and separate signing secrets. If you are taking real payments but only registered an endpoint in test mode, the live endpoint list is empty and live events go nowhere.
The fix Register the endpoint in the mode you are charging in, and set that mode's signing secret (it starts with whsec_) in your production environment variables.
How to tell The payment appears in the Dashboard event list, but the endpoint's delivery log has no attempt for it. Your handler may listen for checkout.session.completed while the endpoint was created with a different event list.
The fix Add the exact event types your handler switches on to the endpoint. Events you do not handle should be unsubscribed, not ignored, to keep the log readable.
How to tell The delivery log shows a 301, 307 or 308. Typical triggers: the apex domain redirecting to www, a trailing-slash setting, or http redirecting to https. A redirect is not a 2xx, so Stripe counts the delivery as failed.
The fix Register the final URL, exactly as it answers with no redirect. Test it with curl -i -X POST https://your-domain/api/webhooks/stripe and confirm you do not get a 3xx.
How to tell The log shows 401 or 403, and the response body is an HTML page. Common sources are Vercel Deployment Protection on a preview URL, and auth middleware (Clerk, NextAuth, Supabase) whose matcher covers every route including the webhook.
The fix Point webhooks at the production URL, not a preview URL. Exclude the webhook path from the auth middleware matcher. The webhook authenticates by signature, not by session.
How to tell The log shows 400 and your function log says "No signatures found matching the expected signature". Three causes account for nearly all of it: you used the whsec_ secret printed by stripe listen against the Dashboard endpoint (or the reverse), you used the wrong mode's secret, or the body was parsed as JSON before it was verified.
The fix Verify against the raw request body. In a Next.js route handler that means await request.text() and passing the string to stripe.webhooks.constructEvent, not request.json(). Use the secret that belongs to the endpoint you are testing.
How to tell The log shows 500 or a timeout. A handler that calls your database, a CRM and an email service in sequence on a serverless function can exceed its time limit, and any unhandled error becomes a 500.
The fix Verify the signature, record the event id, return 2xx quickly, and do the slow work after. Stripe retries failed deliveries on a schedule, and once the handler is fixed you can resend the failed events from the Dashboard.
stripe events resend, and watch the production function log while it arrives. A fix is confirmed only when a real event from the failing mode returns 2xx and the side effect happens once.If the delivery log shows 200s and the app is still wrong, delivery is fine and the bug is in what your handler does with the event. That is ordinary debugging, and an AI coding assistant with the log and the handler in front of it can usually find it. You need a human when the cause is spread across middleware, hosting and handler, or when you have already paid customers waiting.
The webhook is one part of the payment path. A Ship Check reads the whole codebase, so it covers the handler, the middleware in front of it and what happens after the event, and ranks what will break first.
Ship Check, $299: A senior engineer reads your codebase and sends a written verdict (fine, fixable or rewrite), what will break first, a security and data read, and a costed plan, within 48 hours of repo access or it is free. It has a 7-day money-back and is credited against a Ship Fix. Or: Book a call.