VIDEO 9:42

Stripe payment succeeded but the order is still pending: the webhook nobody set up

Published

Length 9:42

Spoken in English

Short answer

When a payment succeeds but the order stays pending, the payment provider took the money and your app was never told. A common cause in the AI-built and vibe-coded apps we reviewed is a webhook that was never registered in the provider’s dashboard. The next causes are duplicate or out-of-order events, fake unsigned requests, timeouts nobody handled, and silent errors. Kevin Riedl, who runs Wavect, walks through each one in a ten-minute video: Wavect has reviewed over 50 vibe-coded products in 2026. The failures shown were reproduced in a simulated shop (Wavect lab simulation), not in a client system.

What the video covers

Stripe payment succeeded but the order never arrived

The money arrived, the order is still pending and nobody got an error. The bugs that hurt most in the products we reviewed sat at the edges, where your code meets someone else’s code. Watch from 0:00

Why isn’t my Stripe webhook arriving? It was never registered

The endpoint must be configured in the provider’s dashboard, not only in your code, and it must be checked in production. Watch from 0:38

What happens when Stripe sends the same webhook twice?

Retries mean the same event can arrive several times, late or out of order; handlers must be idempotent. Watch from 2:26

How do I stop fake webhooks? Verify the signature

A public endpoint needs signature verification, and the AI often has to be told to add it. Watch from 3:25

Request timed out: did the payment go through?

A timeout does not say whether the payment happened. Watch from 4:44

Silent errors and expired API keys: how to notice them

Failures that nobody sees, including expired keys, show up as lost customers. Watch from 5:34

5 questions to ask before you call an integration done

What can go wrong, how do we notice, how do we recover, who gets alerted, how do we test. Watch from 7:20

Frequently asked questions

A common cause is that the webhook endpoint was never registered in the provider’s dashboard (for example Stripe or PayPal). The provider has the money, but your app is never told. It works locally, so nobody notices until real users pay. Check the dashboard for a registered endpoint subscribed to the payment event, and check its delivery log.
If a notification is not delivered successfully, providers keep retrying, so the same event can arrive several times, late, or out of order. If your backend is not idempotent, it registers one payment as several. In our lab simulation, one event delivered twice gave two fulfilments on the naive build and one on the fixed build.
The endpoint has to be public, so anyone can call it. Verify the provider’s webhook signature (IP allowlisting is another mechanism) and tell your AI coding tool to do it explicitly. In our lab simulation, a forged unsigned webhook marked an order as paid on the naive build and was rejected with 400 on the fixed one.
A timeout does not tell you whether the action happened: it may have succeeded, failed, or run later. Plan for all three, for example by looking up the true state at the provider and by using an idempotency key so a retry cannot charge twice.
Five questions: what can go wrong, how do we notice, how do we recover, who gets alerted, and how do we test all of that.

Full transcript

Verbatim transcript of the spoken audio, matching the video captions.

Stripe payment succeeded but the order never arrived

Watch on YouTube · 0:00

This customer paid but the shop never found out.

The money arrived, the order is still pending and nobody got an error or something remotely similar. So nobody actually knows that something is wrong.

Hi, I’m Kevin, I run Wavect and we have reviewed over 50 vibe-coded products this year alone.

And the bugs that really did hurt the most were the ones where it wasn’t about the code itself but rather about the edges when your code interacted with someone else’s code.

Why isn’t my Stripe webhook arriving? It was never registered

Watch on YouTube · 0:38

In many cases, for example, just a webhook wasn’t properly configured when you, for example, have some kind of a payment flow or something like that and the payment event just doesn’t or didn’t arrive.

And a lot of these applications that we have reviewed, especially the fintech ones, for example, there were webhooks when you, for example, pay for a product or service and your application then usually redirects you to an external payment provider. And that payment provider, once the payment has been completed, sends a webhook, basically the notification to your own backend, to your own server that the payment has been completed or that it didn’t complete or any other state in between. And your application then usually reacts to that.

But oftentimes these vibe coders just forget that they have to configure stuff outside of their own application, their own infrastructure as well, for example, on the dashboard from Stripe or PayPal or whatever, just to make sure that they’re actually sending you that notification to your own web application.

So even though everything seems to work locally, you have your tests, you even might have end-to-end testing and all that stuff, still in production, when you actually have real users, it might not arrive.

And you basically have a serious bug because there’s no worse experience on earth than when you buy something and you think you don’t get it. That’s pretty shit, you know.

And also not to forget is that when you test, you usually test the happy path, or that’s basically where your main attention goes.

What happens when Stripe sends the same webhook twice?

Watch on YouTube · 2:26

And the next part is like if one of these payments, for example, or these notifications are not successfully delivered, for example, by Stripe or any other payment provider, they usually keep retrying. So just in case you might have configured everything correctly, but then you receive a notification and for whatever reason your server returns an error code or something didn’t work the way it was supposed to, and Stripe sends another notification, another, another.

And if your backend or your algorithm isn’t idempotent, then you basically register that as multiple payments, even though it’s actually just one payment. And that’s, for obvious reasons, a problem.

And it even gets worse, these notifications might not be in the correct order or in the order that you assumed, it might come late, it might come, as mentioned, multiple times.

How do I stop fake webhooks? Verify the signature

Watch on YouTube · 3:25

And just sticking with that example a little bit, for example, Stripe sends that notification to your backend. If you think about it, that means that endpoint where Stripe sends that notification needs to be public in some sort at least, because otherwise how could an external service on the internet call, send you that notification to your application?

To make sure that not unauthorized or fake payment providers or a malicious user can send you these fake notifications to act as if they’re paid, which is just as bad, just the other way around. And for that, you do have different mechanisms to avoid that, from IP, whitelisting, or webhook signatures, and so on.

But these are things that AI sometimes does, because AI is very smart in applying best practices. But oftentimes, you also have to point these things out explicitly, because your judgment tells you, hey, I need to do that, otherwise I’m going to be fucked or I’m going to be wrecked.

Request timed out: did the payment go through?

Watch on YouTube · 4:44

And there are also oftentimes, let’s say, ambivalent or confusing errors that you get in your application. Let’s say a timeout, great example. For example, if you send a request on external service or external backend, which can be anything, and you get a timeout, you just have the information, okay, the request timed out, like I didn’t get the response, at least not in time.

Which means, in theory, your action, what you actually wanted to do, might have been executed successfully, it failed, or it might be executed at some later point in time, whatever. And these are things, certain edge cases that you have to deal with, and there are many more than you usually imagine.

Silent errors and expired API keys: how to notice them

Watch on YouTube · 5:34

And the worst thing of all, when you build applications, is silent errors. Things that don’t scream at you. Because when your server crashes, you notice, at least when you have users or you use your application yourself. But when something just fails silently, you might not notice at all.

But oftentimes, it might be something that shows off in a different way, which might be users are just not using your service anymore. They’re not registering. They’re not coming back. They’re not buying from your e-commerce store because maybe the payment fails and they just give up on it, whatever.

And these are silent errors which can kill businesses, which can have huge implications in whatever regard of the context of the bug.

So, when you deal with secrets, you obviously want these passwords, API keys, whatever, especially as a vibe coder, or in general it’s just best practice, to expire at some point oftentimes, or most of the time. Because when they are leaked, when they get into the false hands, when they leak into the internet in some capacity, they obviously can be used, and that’s a problem. So when they expire, your application also won’t work, so you have to maintain that as well. So these are also possibly cryptic errors that you might get, like why is something not working anymore? It used to work for weeks, months, years. That’s maintenance.

5 questions to ask before you call an integration done

Watch on YouTube · 7:20

So I like to think about it, let’s say, about four or five key things that you always should think about when you call a feature or product done. The first one would be, what actually could go wrong here, right? When I pay for something, what could go wrong? Well, it could go wrong that the payment doesn’t go through, it goes through twice.

And the next one is, when one of these bad situations is actually happening, how do we notice that? Do we have some kind of monitoring? Do we get a notification? Do we get user feedback in some way, which is also always a great thing to do in general?

And the next one is, how do we recover when something actually goes wrong? When data is corrupted, when we lost data, or when we are not just sure what the true state of the application is. Did the person pay?

What’s right? And these are all things that are real problems in the real world.

The next thing is, maybe you do have all these things, but who gets alerted? Who is responsible for that? Who is responding in time and fixing it and handling it and doing what?

And the last one is, how do we test actually all of that?

And that’s also something vibe coders oftentimes do wrong, especially the ones that came to us. We oftentimes weren’t aware that they launched this thing already with the client. And when they fixed something, they immediately pushed it to production and didn’t even test it. And things were just broken.

So to recap, connecting an API is just the first step at the real work as often is in the boring stuff, which means everything that comes afterwards in the maintenance, in the testing, in the monitoring, everything that makes sure this thing actually works under real pressure.

Sources and simplifications

Provider behaviour follows the providers’ documentation (Stripe, PayPal and others, accessed 2026-11-03). All lab numbers come from one simulated shop (Wavect lab simulation, 2026), not a client system.

Full source list in the video description on YouTube

Want your checkout, webhooks and integrations checked before launch?