BUILD OS · BILLING

Stripe payment succeeded, but the user is still locked out

Short answer

The payment redirect and the application’s access state have likely diverged. Treat the signed server-side payment event as the source for durable entitlements, then check that the event was verified, processed and attached to the correct customer or account.

Symptoms

  • Checkout shows success, while a refresh still shows the paywall.
  • Access appears only after a manual database edit.
  • A retry or duplicate webhook produces inconsistent access.

Why this happens

A browser return URL confirms navigation, not a durable entitlement. Payment state must move through a verified provider event into application-owned state that the authorization layer reads.

Most likely causes

  1. The success page grants access before server confirmation.
  2. The webhook signature or raw request body is handled incorrectly.
  3. The event is recorded but mapped to the wrong user, customer or subscription.
  4. Retries are not idempotent, or the relevant subscription update event is not handled.

How to diagnose it

  1. Inspect the provider event delivery and response for the affected test transaction.
  2. Trace the event ID, Stripe customer ID and internal account ID through the handler and entitlement record.
  3. Replay the event in staging and inspect the resulting durable state.
  4. Check the product’s authorization query after sign-out and sign-in.

Fix

  • Verify the webhook signature before processing.
  • Resolve the internal account from a server-owned customer mapping.
  • Apply the entitlement transition idempotently and persist it.
  • Render access from the durable server state; treat the redirect as a temporary status screen.

Verify the fix

Do not close the issue until these checks pass in the environment that matters:

  • A forged or unsigned request is rejected.
  • The same event delivered twice has one durable effect.
  • A successful payment grants access after a fresh session; a failed, refunded or canceled payment follows the documented policy.
  • A user cannot change a client request to obtain another account’s entitlement.

Related Ship Passport checks

Build School’s production-readiness standard marks this area as proven only with evidence from these checks (it is Build School’s own standard, not an external certification):

  • criticalA successful payment grants access
  • criticalAccess comes from a verified server-side event
  • criticalThe webhook signature is verified
  • criticalA replayed event duplicates nothing
  • importantTest and live keys match their environment

Common false fix

Unlocking the user from the Checkout success page can hide the symptom while leaving refreshes, webhook retries, refunds and direct API requests inconsistent.

Documented evidence

Documenté

Le retour Checkout confirme une navigation ; un événement signé et traité côté serveur confirme un paiement.

Source note: letat-de-paiement-appartient-au-serveur · Updated 2026-09-26. This is documentation provenance; it is not a claim about frequency.

Primary references

Related pattern

The server is the source of truth for access and payment state →

Build OS stage

Billing · Explore Build OS →

Run ShipCheck →Learn the systemGet help fixing it