Guides · Free check · $9 fix pack

Guides

A customer paid but didn't get access. What went wrong?

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.

Cause 1: access is granted on the success page only

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.

Cause 2: the webhook fails silently

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.

The fix Stripe recommends

  1. Write one fulfill(sessionId) function.
  2. Call it from the webhook for checkout.session.completed and checkout.session.async_payment_succeeded.
  3. Also call it from the success page, which is fine as long as it's not the only path.
  4. Inside, retrieve the Checkout Session from the API and check payment_status is not unpaid before granting access.
  5. Make it safe to run more than once: Stripe warns it "might be called multiple times, possibly concurrently, for the same Checkout Session" (source).

Unlocking the customers who already paid

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.

Check yours in 10 seconds (free).

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 check

FAQ

Why did a customer pay but not get access to my app?

Usually 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.

Which Stripe events should grant access after Checkout?

Stripe's fulfillment guide uses checkout.session.completed, plus checkout.session.async_payment_succeeded for delayed payment methods.

Is it OK to also grant access on the success page?

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.

More guides

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.