Software Development

Stripe Webhook Payment Confirmation: Why the Success Page Isn't Proof of Payment

A payment "success" redirect page only proves a browser reached a URL, not that Stripe actually confirmed the charge. Here's why real online stores confirm payment through Stripe's webhook events instead, and what to ask a developer before launch.

By Arnaud Brunel — Founder, Brunel Studios 4 September 2026 Last updated: 4 September 2026
Software Development

Stripe webhook payment confirmation means your server marks an order as paid only after Stripe itself sends a direct, server-to-server event confirming the charge succeeded, not when a customer's browser lands on your "thank you" page. The redirect proves the browser is still open. It does not prove the payment happened, and the two can quietly disagree.

Why a "Payment Successful" Page Isn't Actually Proof of Payment

A checkout redirect only tells you the customer's device reached a URL. It says nothing about whether Stripe actually settled the charge, because the browser and Stripe's payment engine run on two separate timelines. Most checkout flows redirect the browser to a success page as soon as Stripe returns an initial response, which can happen before the payment has fully cleared, especially with card authentication or delayed payment methods.

This is where a lot of online stores get their logic backwards. If an order is marked "paid" the moment the browser hits /thank-you, the store is trusting the customer's device to report an outcome only Stripe's own servers can confirm. A dropped connection or a closed tab between "payment submitted" and "redirect loaded" can break that chain. Stripe's own documentation is explicit that client-side redirects should never be treated as the source of truth for payment status.

A Stripe webhook moves the confirmation off the customer's device entirely. Confirming payment this way is separate from choosing a local payment gateway; getting the gateway right does not solve confirmation reliability on its own. When Stripe processes a payment, it sends an event, typically checkout.session.completed or payment_intent.succeeded, directly from Stripe's servers to an endpoint on your own server. That event is Stripe telling your system, independently of anything the customer's browser does, that the money has actually moved.

The Trade-off Most Guides Skip: Redirects Are Convenient, Webhooks Are Correct

Building on browser redirects alone is faster to ship, and it is wrong in exactly the cases that cost a store the most money. Card declines, expired sessions and abandoned checkouts already drain South African online retail. Stitch's 2025 analysis put South Africa's e-commerce cart abandonment rate at 84%, with 62% of shoppers who hit a payment failure never returning, and cited Mastercard research finding declined card transactions cause roughly 52% of lost online sales. A payment flow that only trusts a redirect is blind to a large share of this activity, since a failed or interrupted payment often never produces a clean redirect at all.

We ran into this directly on a 20-day build for a retailer running both corporate B2B and direct-to-consumer retail sales, the same hybrid dual B2B and D2C ecommerce architecture built to handle corporate code checkout alongside ordinary retail orders on one system. Relying on the browser reaching a success page was never going to hold up once that mixed traffic hit the same checkout, so payment confirmation was built entirely around Stripe's webhook events. The webhook, not the browser, was the only thing allowed to flip an order's status to paid.

The honest trade-off is that webhooks take more work to build correctly. You have to verify the webhook signature, handle Stripe retrying the same event, and make the handler idempotent so a duplicate delivery cannot double-fulfil an order. Skipping that work is how "we use webhooks" quietly becomes just as unreliable as a plain redirect.

What to Ask Your Developer Before Launch

Ask directly whether order status is ever set to paid inside the checkout redirect code, versus only inside the webhook handler. If the answer involves the redirect page at all, that is the gap to close before launch, not after a customer complains their order never arrived despite their card being charged. Also ask how duplicate webhook events are handled, since Stripe will resend an event if your server doesn't acknowledge it fast enough. This is the kind of backend reliability work we scope into custom software development builds for South African ecommerce businesses.

This matters most for stores with real order volume or B2B and B2C traffic sharing one checkout. A small store with very low volume can sometimes get away with weaker confirmation logic for longer, but "get away with it" is not the same as correct.

Webhook-based confirmation is the difference between an order system that reflects what actually happened in Stripe and one that reflects what a browser happened to report. Founders running a store with any meaningful transaction volume should confirm this before launch, not after a support ticket reveals a paid order that never got marked as such.

Questions about Stripe webhook payment confirmation

Why does my Stripe payment succeed but the order still doesn't show as paid?

This usually happens when your store marks orders paid based on the browser reaching a redirect page instead of a confirmed webhook event. If the redirect fails to load, the browser closes, or the connection drops, Stripe can have a successful charge your own system never learns about.

Is it safe to mark an order as paid just from Stripe's success/redirect page?

No. The redirect only confirms the customer's browser reached a URL, not that Stripe settled the payment. Stripe's own guidance is clear that client-side redirects should never be treated as the source of truth; only a server-to-server webhook event confirms the actual payment outcome.

What is a Stripe webhook and why does an online store need one?

A Stripe webhook is an event Stripe's own servers send directly to your server when something happens on a payment, such as payment_intent.succeeded. Stores need one because it is the only independent confirmation that a charge actually completed, rather than relying on the customer's device to report it.

What happens if a customer closes their browser tab right after paying?

Nothing changes on Stripe's side. The payment can still succeed and Stripe still sends the webhook event confirming it. If order logic depends only on the browser reaching the redirect page, though, that closed tab means the order may never get marked paid at all.

Can a customer's payment succeed in Stripe but never reach the store's own system?

Yes, if the store only listens for a browser redirect. On a build handling mixed corporate and retail checkout traffic, we routed payment confirmation through Stripe's webhook rather than the redirect, because redirect delivery could not be trusted to reflect what actually happened in Stripe.

How do you test that Stripe webhooks are working before an online store goes live?

Use Stripe's CLI or dashboard to send test webhook events to your endpoint and confirm your server responds correctly and updates order status. Also interrupt a test checkout on purpose, close the tab before the redirect loads, and confirm the order still gets marked paid once the event arrives.

Do South African online stores need Stripe webhooks, or is the payment success page enough?

Webhooks are needed for any store taking real transaction volume. The success page alone cannot account for dropped connections or failed redirects, and with card declines already driving over half of lost online sales in South Africa, order logic cannot afford to quietly lose track of genuine payments.

Arnaud Brunel

Founder, Brunel Studios

Arnaud Brunel is the founder of Brunel Studios, a software product studio based in Cape Town. He has spent the last 8 years building digital products for founders and SMEs across South Africa and Africa, working across mobile, web and AI-native platforms.

LinkedIn ↗