Payments work in test but not live
The test payment goes through and the real one does not. Five causes, one of which is so common it is worth checking first.
Payments are the part where 'nearly working' costs the most. A list that does not load costs you a complaint; a payment that gets collected but never arrives in your system costs you a customer. Fortunately the causes are few.
1. You did not switch the keys
By far the most common, and the easiest to miss because nothing breaks: with test keys on your live site everything works, only no real money ever moves. Test keys and live keys look alike; the difference is usually one word inside the key itself. Check both, including the webhook's.
2. The webhook still points at your test environment
The payment provider tells your app that a payment came in. If that address still points at your preview link or at localhost, the payment does get collected, but your app never hears about it. Symptom: money in, order stuck on 'pending'. This is why your customer calls while your dashboard says everything went fine.
3. The webhook arrives but gets rejected
Every notification is signed, and the key you verify that signature with is a different one from your normal key, and differs between test and live as well. If it does not match, your app rejects every notification. All payment providers show in their dashboard what they sent and what your app answered; it is spelled out there.
4. Your account is not approved yet
Taking live payments requires an approved account: company details, a bank account, sometimes an identity check. While that is pending, test mode works and the real thing does not. This takes days, not minutes, so start it before you want to go live.
5. Payment methods other than the one you tested
In the Netherlands most people pay with iDEAL, which works differently from a card: the customer leaves for their bank and comes back. If you only test with a test card, you never test the path your customers actually take, including the case where they drop out halfway.
The order to check it in
- Check your payment provider's dashboard for the payment. If it is not there, it is cause 1 or 4.
- If it is there: check the webhooks for whether your app answered. No attempt is cause 2, a rejected attempt is cause 3.
- Always make one real payment of one euro to yourself, with the method your customers use. You can refund it, but the transaction fee on it does not come back; that test costs you a few cents, not a euro.
Test mode proves your code is right. Only a real euro proves your setup is right.
Which provider fits best is covered in choosing Stripe or Mollie. If you are stuck on the integration itself, send over what you are seeing; this is usually a matter of hours, not days.