← Back to the blog

Payments and webhooks: what matters after the pay button

Imagine you’ve just paid and the screen keeps waiting. Is your booking confirmed? Should you try again? That uncertainty is unsettling. Behind the scenes, someone else may be trying to find an answer for you. When connecting payments, I think it’s essential to consider both people: the person buying and the person who needs to understand what happened so they can help.

An illustration of a receipt, a validated event and an order record connected together.
The payment notification is checked before the order is updated. AI-generated conceptual illustration; it does not show a real transaction.

What a payment notification tells you

A webhook is a notification a service sends to your application when something happens. Stripe uses them, for example, to communicate a bank confirmation or a dispute that arrives later. The notification brings information about what happened; the application has to connect it to the order and decide what to do.Stripe: receiving and processing webhooks ↗

I’ll come back to that booking. The person returns to the site after paying and wants to know whether it’s ready. Reaching that screen is not enough to confirm it. The application needs to recognize the provider’s confirmation and know which booking it belongs to.

If that confirmation hasn’t arrived yet, the message should explain that calmly and tell the person what comes next. “Your payment is being checked” can be more helpful than an empty screen, as long as it describes what’s actually happening. And before asking someone to pay again, the earlier attempt needs to be checked.

Before confirming, check which order it belongs to

Stripe requires verifying the notification’s signature using the original, unmodified request body. That check helps verify where it came from. Then there’s another task: reading what it says and checking whether the application should process it.Stripe: receiving and processing webhooks ↗

For the booking, I’d check that the payment identifier matches the expected order and that its confirmation conditions have been met. Receiving a genuine notification isn’t enough to confirm just any booking. Keeping that relationship also gives the team somewhere to start if they need to help the customer.

What if the notification arrives twice?

Stripe warns that a webhook can arrive more than once and that delivery order is not guaranteed. The application therefore needs to recognize what it has already processed. It also needs to stop an older notification from moving a confirmed order back to an earlier state.Stripe: receiving and processing webhooks ↗

Another situation occurs when the application sends a request to Stripe, loses the response and tries again. Stripe offers idempotency keys to recognize retries of the same operation, subject to the conditions of the API being used. This mechanism and the handling of repeated notifications address different parts of the process.Stripe: idempotent requests ↗

For the booking in this example, receiving the same notification twice shouldn’t cause two confirmations. And if the person changes their purchase, I’d check whether it’s a new operation. Keeping the charge attempt separate from the notifications received makes it easier to understand what is being repeated in each case.

Give the team a way to help

When a notification arrives, it’s worth saving it durably before acknowledging receipt. The application can then process it and keep a way to resume the work if it fails. That leaves a path for reviewing pending work, rather than depending on everything going right the first time.

The person helping the customer needs to know which booking is waiting for confirmation, what happened with the payment and which reference to look up. Sometimes checking the existing status or correcting an association will be enough. Making those options clear means “try paying again” doesn’t have to be the only answer available.

I’ve worked with PHP and Laravel on Stripe integrations for different clients. Each product needs to decide when to confirm a purchase, how to cancel it and what to do if something remains pending. The library helps me connect the pieces; those decisions require understanding how the business works and what the buyer expects.

Look at the process again as a customer

Before handing it over, I’d test a complete booking. Then I’d send the same notification twice, let an old one arrive and cause a failure after saving an event. For each test, I’d check the booking’s status and the message the person sees, along with the server’s response.

At the end, I’d return to the opening question: if I pay and something takes a while, do I understand what’s happening? And if I ask for help, can someone give me an informed answer? Taking care of those two questions is a very practical way to respect the trust someone places in the product when they decide to pay.

Sources and further reading