Payment code is the part of a fintech build where "it worked when I tested it" and "it works on launch day with a stranger's real card" are dangerously different claims. These five mistakes are the ones we see most often when we're brought in to review or rescue an existing integration.
Mistake 1: Letting card data touch your own servers
Some early-stage teams build a form that submits card numbers directly to their own backend before forwarding them to a processor. This is both a security liability and drags you into the heaviest tier of PCI-DSS compliance for no benefit. The fix: use the processor's hosted fields or SDK so raw card data never passes through code you wrote — Stripe Elements and PayPal's SDKs both do this correctly out of the box.
Mistake 2: Using floating-point numbers for money
A shocking number of payment bugs trace back to storing `19.99` as a JavaScript float instead of `1999` cents as an integer. Floating-point arithmetic cannot represent most decimal fractions exactly, so totals drift by fractions of a cent — invisible in a demo, very visible when your monthly reconciliation report doesn't balance. Every serious fintech build uses integer-cents or fixed-point decimal arithmetic, full stop.
Mistake 3: No idempotency keys, leading to double charges
When a network request times out, a naive client retries it — and if the first charge actually succeeded before the timeout, the customer gets charged twice. Idempotency keys (a unique identifier attached to each payment attempt that the processor uses to recognize and discard duplicates) solve this completely, and Stripe and PayPal both support them natively. Skipping this is one support-ticket away from a very bad customer experience.
Mistake 4: Trusting client-side confirmation instead of verifying webhooks
If your app marks an order as "paid" the moment the browser says the payment succeeded, you are trusting a channel that a user's flaky connection, a browser extension, or genuine bad actors can interfere with. The correct pattern is to treat the processor's signed webhook as the source of truth for payment status, verify its signature, and only then update your database.
Mistake 5: Assuming one gateway serves every market equally well
Stripe and PayPal cover an enormous share of the world well — but well is not everywhere. Teams that force a single gateway onto every target market often see mysteriously high decline rates in specific countries. The fix isn't always a second integration; sometimes it's confirming the primary gateway's actual coverage before launch instead of assuming it.
If any of these sound familiar in your own codebase, a focused payment integration review is usually far cheaper than the damage of discovering them in production. And if you're building from scratch, this is exactly the checklist we build against for every fintech and SaaS project, under the same escrow-protected terms as everything else we deliver.