This is almost always one of two design problems: access is granted only on the success page, or the webhook that should grant it is failing.
Stripe is explicit: "You can't rely on triggering fulfillment only from your checkout landing page, because it's not guaranteed customers visit that page. For example, a customer can pay successfully and then lose their internet connection before your landing page loads." (Stripe docs: Fulfill orders). Closed tabs, slow mobile networks and in-app browsers all cause this.
If the webhook endpoint returns a redirect, a login wall or a signature error, Stripe records a failed delivery and your database never hears about the payment. Check the endpoint's delivery log in the Dashboard. See the 7-step checklist.
fulfill(sessionId) function.checkout.session.completed and checkout.session.async_payment_succeeded.payment_status is not unpaid before granting access.Find the payments in the Dashboard (or list recent Checkout Sessions), and run your fulfill function for each session ID. If you're refunding instead, refund from the Dashboard or API.
Paste your webhook URL. WebhookProof sends 3 harmless test requests and tells you whether Stripe can reach it and whether it rejects unsigned events.
Run the free checkUsually because access is granted only when the buyer lands on the success page, or because the webhook that should grant access is failing. Stripe says you cannot rely on the landing page alone.
Stripe's fulfillment guide uses checkout.session.completed, plus checkout.session.async_payment_succeeded for delayed payment methods.
Yes, as long as the webhook is also wired up and your fulfillment function is safe to run more than once for the same session.
Stripe webhook not working? Check these 7 things in order · Stripe webhook signature verification failed · Stripe webhook getting a 307 or 308 redirect · Stripe webhook on Supabase Edge Functions: fixing 401s and signature errors
Last reviewed 2026-10-18. WebhookProof is an independent tool, not affiliated with Stripe, Inc. Quotes are from the linked documentation.