What is Stripe?
A popular payments service. It charges cards and tells your app what happened through webhooks.
Where Stripe goes wrong in real apps
Each of these is a short scenario built from a real failure in an app made with AI. Read the answer here, or walk through it yourself in about four minutes.
Getting paid · 4 minutes · Free
The success page anyone could visit
Your app has 41 Pro accounts. Stripe shows 29 paying customers. Nobody hacked anything: twelve people just typed an address.
Walk it, freeShould I grant access on the Stripe success page?
No. The success page is just where the browser lands after checkout, and anyone can type its address, so granting access there gives your paid plan away. Grant access in your webhook when Stripe sends checkout.session.completed, verified by its signature. Let the success page only read and display the plan your database already holds.
Don't trust the browser · 4 minutes · Pro
The webhook anyone could send
Twelve accounts upgraded to Pro overnight. Stripe shows no payments from any of them.
Read the fixWhy must I verify Stripe webhook signatures?
Because your webhook URL is public and anyone can send it a fake 'checkout completed' event with their own user id. Stripe signs every event with your webhook signing secret. Verify the Stripe-Signature header with stripe.webhooks.constructEvent using the raw request body, reject anything that fails, and only then grant access or credits.
Getting paid · 4 minutes · Pro
The webhook that failed every time
Payments work. Upgrades don't. Stripe's dashboard shows every webhook to your app failing with a 400.
Read the fixWhy does Stripe webhook verification fail?
The signature covers the exact raw bytes Stripe sent. It fails when your code parses the body as JSON before verifying, or when it uses the wrong signing secret. In Next.js App Router, read the body with request.text() and pass it unchanged to constructEvent. Each endpoint, including the Stripe CLI, has its own whsec_ secret.
Money and secrets · 5 minutes · Pro
The webhook that arrived twice
A customer bought one month of credits. Their account shows two months. Your Stripe dashboard shows one payment.
Read the fixWhy did my Stripe webhook run twice?
Stripe delivers webhooks at least once and retries when your endpoint is slow or fails, so the same event id can arrive twice. Record each processed event id in a table with a unique key and skip repeats, and always verify the signature against the raw request body.
Getting paid · 4 minutes · Pro
Two subscriptions, one person
A customer is being charged twice a month. Stripe shows two customers with their email, each with an active Pro subscription.
Read the fixWhy does Stripe create duplicate customers?
Stripe Checkout creates a new customer every time unless you pass an existing customer id. Passing only customer_email fills in the form but still creates a new customer, so a user who checks out twice gets two customers and possibly two subscriptions. Create one customer per user, store its id, and check for an active plan before checkout.
Getting paid · 4 minutes · Pro
The card that bounced
Your revenue dropped 15% this month, but nobody cancelled. In Stripe, a row of subscriptions has quietly ended.
Read the fixWhat happens when a Stripe renewal payment fails?
Stripe marks the invoice failed, sets the subscription to past_due and retries on a schedule. If no retry succeeds, the subscription is cancelled or marked unpaid, depending on your settings. Customers who were never told often lose access without deciding to leave. Email them, show an in-app banner with a card update link, and keep access during retries.
Related terms
- Webhook
- A message another service (like Stripe) sends to your server to say something happened, such as 'this customer paid'.
- Request
- A message your browser (or any program) sends to a server asking for something: 'give me invoice 105' or 'save this profile'.
- Server
- A computer that runs your app's code out of sight. Users can't change what happens there, which is why checks belong there.
- Table, row, column
- A table is like one spreadsheet (orders). Each row is one item (one order); each column is one detail (price, date).
- API
- The part of an app that other programs talk to. Your app's pages ask its API for data, like a waiter taking orders to a kitchen.
- Browser
- Chrome, Safari and friends. Everything that runs here is visible to, and changeable by, the person using it.