Payments
Why a payment succeeds but the order goes missing
The customer has paid, the money has left their account, and your system shows nothing. Here is why that happens and how it is prevented.
The short version
- A payment is confirmed twice: once through the customer’s browser and once server to server. Only the second is reliable.
- Webhooks can arrive late, twice or out of order, so the code that receives them has to expect all three.
- A daily reconciliation job is the safety net that catches whatever slips through.
Two messages, not one
After a customer pays, the gateway tries to tell your website in two ways. First, it sends the customer’s browser back to your site with the result. Second, it sends a message directly from its own servers to yours. That second message is called a webhook.
Many integrations rely only on the first. It works in every test, because the developer always waits for the page to load. Real customers don’t. They close the tab as soon as their bank app says “paid”, their phone drops from Wi-Fi to mobile data, or the bank’s page never redirects back. The money has moved, but your site never heard about it.
Why the webhook is the source of truth
The webhook doesn’t depend on the customer’s phone, browser or patience. The gateway sends it from its own servers and keeps retrying, often for hours, until your server confirms it was received. An order should move to “paid” when a verified webhook says so. The browser redirect is only there to show the customer a thank-you page.
What a careful integration does
- Checks the signature. Every webhook is signed with a secret only you and the gateway know. Unsigned or wrongly signed messages are rejected, so nobody can fake a payment.
- Saves first, works later. The message is stored and acknowledged immediately. Emails, stock updates and invoices happen afterwards, so a slow step can’t cause a timeout and a lost event.
- Expects repeats. Gateways send the same event more than once on purpose. Processing it twice must change nothing: no second email, no double stock deduction.
- Doesn’t trust the order of arrival. A “refunded” event can arrive before “captured”. The order’s history decides its state, not whichever message came last.
The safety net: reconciliation
Even a well-built integration can miss an event. Your server was down for maintenance, or the gateway had an incident of its own. That is why we add a scheduled job that asks the gateway for its list of payments and compares it with yours. Anything paid at the gateway but still pending on your side is corrected and reported.
Signs your current set-up has this problem
- Customers email screenshots of a successful payment for orders you can’t find.
- Staff mark orders as paid by hand after checking the gateway’s dashboard.
- Sales totals and bank deposits differ, and nobody can explain the gap.
- Problems cluster on mobile and on slow connections.
If any of these sound familiar, the fix is usually a few days of work, not a rebuild.