whocanfixmyapp

Home / Problems / Payments

Customer paid but their account was not upgraded

VC-32StripeSupabaseUpdated October 2026By

Quick verdict

Get an engineer for this one. Needs a server endpoint and a signature check.

How serious
High
Fix it yourself?
No, get an engineer
Typical cost
€99–$990 for a single fix (prices)
Top rated for Supabase
Redlab · 10.0/10

What you see. Stripe shows a successful payment, but the customer's account still says Free and they email you asking for access.

Why it happens

Stripe does not update your database. After checkout, Stripe sends a webhook, a signed message to an address on your server, carrying the event checkout.session.completed. Your code must receive it, verify the Stripe-Signature header with the whsec_ signing secret, and then mark the account as paid. Stripe says you cannot rely on the success page, because the customer may lose their connection before it loads.

Three things break this chain. The endpoint was never registered in the Stripe dashboard, or only in the sandbox, and live mode has its own endpoints. The signing secret in your host's environment came from the CLI or the sandbox, so verification fails with a 400. Or the handler runs but updates the wrong user, because the checkout session never carried your user's id. Stripe retries failed deliveries for up to three days in live mode, so fixing the endpoint often recovers the missed events.

Fix it yourself

  1. In the Stripe dashboard, switch to live mode and open Developers → Webhooks. If no endpoint lists your live domain, that is the problem.
  2. Click the endpoint and open Event deliveries. A 400 means signature verification failed, a 404 means the address is wrong, and no events means nothing is registered.
  3. Click Reveal secret and compare the whsec_ value with STRIPE_WEBHOOK_SECRET in your host's environment settings. They differ between sandbox and live.
  4. Check the endpoint subscribes to checkout.session.completed and, for subscriptions, invoice.paid and customer.subscription.updated.
  5. After fixing, click Resend on each failed event. Stripe allows this for 15 days. The customer should be upgraded within seconds.
  6. Until then, upgrade affected customers by hand in your database and keep a list of who you touched.

When to get an engineer

Hire now if customers have paid and are waiting, since every day adds refund requests and disputes. Tell the engineer your live endpoint address, where the app is hosted, and whether the webhook runs in a Supabase edge function or in your app's own server. A single fix at €99–$990 usually takes 1–3 days and should include tests for the paid flow, our item CODE-02, so the next deploy cannot silently break it again.

Top-rated companies for Supabase apps

Ranked by our score: published prices, scope of work, AI tools named, timing and a low-risk first step. How we score.

  • 1Redlab10.0/10Best for: A full rescue by one team that keeps buildingFree first step · from $490
  • 2Vibe Code Rescue (Lev Arakelyan)9.0/10Best for: A one-off check and a cleanupFrom $299
  • 3LazyCodeLab9.0/10Best for: A one-off check and a cleanupFrom $399

All 29 Supabase companies, ranked

Check these

PAY-01Critical

Paid accounts are unlocked by a verified payment webhook

Access should change only when your server receives a signed webhook from Stripe or your provider, not when the browser reaches a success page.

PAY-04Medium

Failed payments, cancellations and refunds are tested

Use your provider's test cards for declines and disputes, then check what the user sees and what access they keep.

CODE-02Medium

The flows that make money have tests

Sign-up, checkout and the core action. A few end-to-end tests catch most regressions from new prompts.

OPS-03High

Errors reach you before users do

Add error monitoring and uptime alerts. If you learn about outages from customers, this is missing.

OPS-04Medium

Secrets live in the host's environment settings

Keys belong in environment variables on the server, not in the repository or in front-end code.

Questions

Can I just upgrade the user on the success page instead?

Stripe says no. Customers can pay and never reach that page, and anyone can open the success URL without paying. Use the page for speed, but the verified webhook must be the thing that grants access.

Why did it work in test mode?

Your sandbox endpoint and its signing secret were set up during development. Live mode needs its own endpoint and its own whsec_ secret, and the agent rarely creates those.

Sources: Stripe: Fulfill orders; Stripe: Receive events in your webhook endpoint; Stripe: Go-live checklist.